From d1b194430c9d523f034428531d0f0b08ea427d55 Mon Sep 17 00:00:00 2001 From: Petrik de Heus Date: Mon, 1 Jul 2024 19:49:42 +0200 Subject: [PATCH 001/204] [rails] Don't bulk update on MySQL (#9122) The benchmarks currently don't take into account batch updates in MySQL. This fixes the flaky MySQL updates verification. --- frameworks/Ruby/rails/app/models/world.rb | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/frameworks/Ruby/rails/app/models/world.rb b/frameworks/Ruby/rails/app/models/world.rb index 278501c05f4..bc1c8e9311b 100644 --- a/frameworks/Ruby/rails/app/models/world.rb +++ b/frameworks/Ruby/rails/app/models/world.rb @@ -3,4 +3,14 @@ class World < ApplicationRecord alias_attribute(:randomNumber, :randomnumber) \ if connection.adapter_name.downcase.start_with?('postgres') + + if connection.adapter_name.downcase.start_with?('trilogy') + def self.upsert_all(attributes, on_duplicate: :update, update_only: nil, returning: nil, unique_by: nil, record_timestamps: nil) + # On MySQL Batch updates verification isn't supported yet by TechEmpower. + # https://github.com/TechEmpower/FrameworkBenchmarks/issues/5983 + attributes.each do |attrs| + where(id: attrs[:id]).update_all(randomNumber: attrs[:randomNumber]) + end + end + end end From 7388a89641eeddebcb9aff6a4f8c079fa64ef139 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=80=97=E5=AD=90?= Date: Tue, 2 Jul 2024 01:49:52 +0800 Subject: [PATCH 002/204] [New Framework]: Goravel (#9125) * feat: add goravel test case * feat: optimize code * fix: query with pool --- frameworks/Go/goravel/README.md | 44 + frameworks/Go/goravel/benchmark_config.json | 55 + .../Go/goravel/goravel-fiber.dockerfile | 21 + frameworks/Go/goravel/goravel.dockerfile | 19 + frameworks/Go/goravel/src/fiber/.env | 1 + .../app/http/controllers/test_controller.go | 126 ++ .../src/fiber/app/http/controllers/utils.go | 107 ++ .../Go/goravel/src/fiber/app/models/world.go | 10 + .../app/providers/route_service_provider.go | 16 + frameworks/Go/goravel/src/fiber/config/app.go | 40 + .../Go/goravel/src/fiber/config/cache.go | 18 + .../Go/goravel/src/fiber/config/database.go | 32 + .../Go/goravel/src/fiber/config/http.go | 26 + .../Go/goravel/src/fiber/config/json.go | 31 + frameworks/Go/goravel/src/fiber/go.mod | 191 +++ frameworks/Go/goravel/src/fiber/go.sum | 1170 +++++++++++++++++ frameworks/Go/goravel/src/fiber/main.go | 27 + frameworks/Go/goravel/src/fiber/routes/web.go | 19 + .../Go/goravel/src/fiber/templates/fortune.go | 53 + .../goravel/src/fiber/templates/fortune.qtpl | 15 + .../src/fiber/templates/fortune.qtpl.go | 81 ++ frameworks/Go/goravel/src/gin/.env | 1 + .../app/http/controllers/test_controller.go | 129 ++ .../src/gin/app/http/controllers/utils.go | 101 ++ .../Go/goravel/src/gin/app/models/fortune.go | 10 + .../Go/goravel/src/gin/app/models/world.go | 10 + .../app/providers/route_service_provider.go | 16 + frameworks/Go/goravel/src/gin/config/app.go | 40 + frameworks/Go/goravel/src/gin/config/cache.go | 18 + .../Go/goravel/src/gin/config/database.go | 32 + frameworks/Go/goravel/src/gin/config/http.go | 30 + frameworks/Go/goravel/src/gin/config/json.go | 31 + frameworks/Go/goravel/src/gin/go.mod | 194 +++ frameworks/Go/goravel/src/gin/go.sum | 1170 +++++++++++++++++ frameworks/Go/goravel/src/gin/main.go | 27 + .../src/gin/resources/views/fortunes.tmpl | 22 + frameworks/Go/goravel/src/gin/routes/web.go | 19 + 37 files changed, 3952 insertions(+) create mode 100644 frameworks/Go/goravel/README.md create mode 100644 frameworks/Go/goravel/benchmark_config.json create mode 100644 frameworks/Go/goravel/goravel-fiber.dockerfile create mode 100644 frameworks/Go/goravel/goravel.dockerfile create mode 100644 frameworks/Go/goravel/src/fiber/.env create mode 100644 frameworks/Go/goravel/src/fiber/app/http/controllers/test_controller.go create mode 100644 frameworks/Go/goravel/src/fiber/app/http/controllers/utils.go create mode 100644 frameworks/Go/goravel/src/fiber/app/models/world.go create mode 100644 frameworks/Go/goravel/src/fiber/app/providers/route_service_provider.go create mode 100644 frameworks/Go/goravel/src/fiber/config/app.go create mode 100644 frameworks/Go/goravel/src/fiber/config/cache.go create mode 100644 frameworks/Go/goravel/src/fiber/config/database.go create mode 100644 frameworks/Go/goravel/src/fiber/config/http.go create mode 100644 frameworks/Go/goravel/src/fiber/config/json.go create mode 100644 frameworks/Go/goravel/src/fiber/go.mod create mode 100644 frameworks/Go/goravel/src/fiber/go.sum create mode 100644 frameworks/Go/goravel/src/fiber/main.go create mode 100644 frameworks/Go/goravel/src/fiber/routes/web.go create mode 100644 frameworks/Go/goravel/src/fiber/templates/fortune.go create mode 100644 frameworks/Go/goravel/src/fiber/templates/fortune.qtpl create mode 100644 frameworks/Go/goravel/src/fiber/templates/fortune.qtpl.go create mode 100644 frameworks/Go/goravel/src/gin/.env create mode 100644 frameworks/Go/goravel/src/gin/app/http/controllers/test_controller.go create mode 100644 frameworks/Go/goravel/src/gin/app/http/controllers/utils.go create mode 100644 frameworks/Go/goravel/src/gin/app/models/fortune.go create mode 100644 frameworks/Go/goravel/src/gin/app/models/world.go create mode 100644 frameworks/Go/goravel/src/gin/app/providers/route_service_provider.go create mode 100644 frameworks/Go/goravel/src/gin/config/app.go create mode 100644 frameworks/Go/goravel/src/gin/config/cache.go create mode 100644 frameworks/Go/goravel/src/gin/config/database.go create mode 100644 frameworks/Go/goravel/src/gin/config/http.go create mode 100644 frameworks/Go/goravel/src/gin/config/json.go create mode 100644 frameworks/Go/goravel/src/gin/go.mod create mode 100644 frameworks/Go/goravel/src/gin/go.sum create mode 100644 frameworks/Go/goravel/src/gin/main.go create mode 100644 frameworks/Go/goravel/src/gin/resources/views/fortunes.tmpl create mode 100644 frameworks/Go/goravel/src/gin/routes/web.go diff --git a/frameworks/Go/goravel/README.md b/frameworks/Go/goravel/README.md new file mode 100644 index 00000000000..f9b0d413503 --- /dev/null +++ b/frameworks/Go/goravel/README.md @@ -0,0 +1,44 @@ +# Goravel Benchmarking Test + +[Goravel](https://www.goravel.dev/) is a web application framework with complete functions and excellent scalability. As a starting scaffolding to help Gopher quickly build their own applications. + +The framework's design is consistent with [Laravel](https://github.com/laravel/laravel), simplifying the learning curve for PHPers. Kudos to Laravel! + +### Test Type Implementation Source Code + +* [JSON](src/gin/app/http/controllers/test_controller.go) +* [PLAINTEXT](src/gin/app/http/controllers/test_controller.go) +* [DB](src/gin/app/http/controllers/test_controller.go) +* [QUERY](src/gin/app/http/controllers/test_controller.go) +* [CACHED QUERY](src/gin/app/http/controllers/test_controller.go) +* [UPDATE](src/gin/app/http/controllers/test_controller.go) +* [FORTUNES](src/gin/app/http/controllers/test_controller.go) + +## Test URLs +### JSON + +http://localhost:8080/json + +### PLAINTEXT + +http://localhost:8080/plaintext + +### DB + +http://localhost:8080/db + +### QUERY + +http://localhost:8080/query?q= + +### CACHED QUERY + +http://localhost:8080/cached_query?q= + +### UPDATE + +http://localhost:8080/update?q= + +### FORTUNES + +http://localhost:8080/fortunes diff --git a/frameworks/Go/goravel/benchmark_config.json b/frameworks/Go/goravel/benchmark_config.json new file mode 100644 index 00000000000..bcb01875139 --- /dev/null +++ b/frameworks/Go/goravel/benchmark_config.json @@ -0,0 +1,55 @@ +{ + "framework": "goravel", + "tests": [ + { + "default": { + "json_url": "/json", + "db_url": "/db", + "query_url": "/queries?q=", + "fortune_url": "/fortunes", + "cached_query_url": "/cached-worlds?q=", + "update_url": "/update?q=", + "plaintext_url": "/plaintext", + "port": 8080, + "approach": "Realistic", + "classification": "Fullstack", + "database": "postgres", + "framework": "goravel", + "language": "Go", + "flavor": "None", + "orm": "Full", + "platform": "None", + "webserver": "None", + "os": "Linux", + "database_os": "Linux", + "display_name": "Goravel Gin", + "notes": "", + "versus": "go" + }, + "fiber": { + "json_url": "/json", + "db_url": "/db", + "query_url": "/queries?q=", + "fortune_url": "/fortunes", + "cached_query_url": "/cached-worlds?q=", + "update_url": "/update?q=", + "plaintext_url": "/plaintext", + "port": 8080, + "approach": "Realistic", + "classification": "Fullstack", + "database": "postgres", + "framework": "goravel", + "language": "Go", + "flavor": "None", + "orm": "Full", + "platform": "None", + "webserver": "None", + "os": "Linux", + "database_os": "Linux", + "display_name": "Goravel Fiber", + "notes": "", + "versus": "go" + } + } + ] +} diff --git a/frameworks/Go/goravel/goravel-fiber.dockerfile b/frameworks/Go/goravel/goravel-fiber.dockerfile new file mode 100644 index 00000000000..91d583dface --- /dev/null +++ b/frameworks/Go/goravel/goravel-fiber.dockerfile @@ -0,0 +1,21 @@ +FROM golang:1.22-alpine + +ENV GO111MODULE=on \ + CGO_ENABLED=0 \ + GOAMD64=v3 \ + GOARCH="amd64" \ + GOOS=linux + +WORKDIR /go/goravel + +COPY ./src/fiber /go/goravel + +RUN go mod tidy + +RUN go generate -x ./templates + +RUN go build -ldflags '-s -w --extldflags "-static"' -o /go/goravel/main + +EXPOSE 8080 + +CMD /go/goravel/main diff --git a/frameworks/Go/goravel/goravel.dockerfile b/frameworks/Go/goravel/goravel.dockerfile new file mode 100644 index 00000000000..2000cbbcf35 --- /dev/null +++ b/frameworks/Go/goravel/goravel.dockerfile @@ -0,0 +1,19 @@ +FROM golang:1.22-alpine + +ENV GO111MODULE=on \ + CGO_ENABLED=0 \ + GOAMD64=v3 \ + GOARCH="amd64" \ + GOOS=linux + +WORKDIR /go/goravel + +COPY ./src/gin /go/goravel + +RUN go mod tidy + +RUN go build -tags="sonic avx" -ldflags '-s -w --extldflags "-static"' -o /go/goravel/main + +EXPOSE 8080 + +CMD /go/goravel/main diff --git a/frameworks/Go/goravel/src/fiber/.env b/frameworks/Go/goravel/src/fiber/.env new file mode 100644 index 00000000000..9ceb9e63dc9 --- /dev/null +++ b/frameworks/Go/goravel/src/fiber/.env @@ -0,0 +1 @@ +APP_KEY=abcdefghijklmnopqrstuvwxyz123456 \ No newline at end of file diff --git a/frameworks/Go/goravel/src/fiber/app/http/controllers/test_controller.go b/frameworks/Go/goravel/src/fiber/app/http/controllers/test_controller.go new file mode 100644 index 00000000000..c433f221e7b --- /dev/null +++ b/frameworks/Go/goravel/src/fiber/app/http/controllers/test_controller.go @@ -0,0 +1,126 @@ +package controllers + +import ( + "math/rand/v2" + "sort" + + "github.com/goravel/framework/contracts/http" + "github.com/goravel/framework/facades" + + "goravel/templates" +) + +type TestController struct{} + +func NewTestController() *TestController { + initCache() + return &TestController{} +} + +func (r *TestController) Plaintext(ctx http.Context) http.Response { + Plaintext(ctx, helloworld) + return nil +} + +func (r *TestController) JSON(ctx http.Context) http.Response { + message := acquireMessage() + message.Message = helloworld + + JSON(ctx, &message) + releaseMessage(message) + return nil +} + +func (r *TestController) DB(ctx http.Context) http.Response { + world := acquireWorld() + + world.ID = r.getRand() + _ = facades.Orm().Query().Find(&world) + + JSON(ctx, &world) + releaseWorld(world) + return nil +} + +func (r *TestController) Queries(ctx http.Context) http.Response { + n := r.getN(ctx) + worlds := acquireWorlds()[:n] + + for i := 0; i < n; i++ { + worlds[i].ID = r.getRand() + _ = facades.Orm().Query().Find(&worlds[i]) + } + + JSON(ctx, &worlds) + releaseWorlds(worlds) + return nil +} + +func (r *TestController) Update(ctx http.Context) http.Response { + n := r.getN(ctx) + worlds := acquireWorlds()[:n] + + for i := 0; i < n; i++ { + worlds[i].ID = r.getRand() + _ = facades.Orm().Query().Find(&worlds[i]) + } + + // sorting is required for insert deadlock prevention. + sort.Slice(worlds, func(i, j int) bool { + return worlds[i].ID < worlds[j].ID + }) + + tx, _ := facades.Orm().Query().Begin() + for i := 0; i < n; i++ { + worlds[i].RandomNumber = r.getRand() + _ = tx.Save(&worlds[i]) + } + _ = tx.Commit() + + JSON(ctx, &worlds) + releaseWorlds(worlds) + return nil +} + +func (r *TestController) Fortunes(ctx http.Context) http.Response { + fortunes := make([]templates.Fortune, 0) + _ = facades.Orm().Query().Table("Fortune").Get(&fortunes) + + fortunes = append(fortunes, templates.Fortune{Message: "Additional fortune added at request time."}) + sort.Slice(fortunes, func(i, j int) bool { + return fortunes[i].Message < fortunes[j].Message + }) + + HTML(ctx) + templates.WriteFortunePage(ctx.Response().Writer(), fortunes) + return nil +} + +func (r *TestController) CacheQueries(ctx http.Context) http.Response { + n := r.getN(ctx) + worlds := acquireWorlds()[:n] + cached := facades.Cache().Get("worlds").(Worlds) + + for i := 0; i < n; i++ { + worlds[i] = cached[r.getRand()-1] + } + + JSON(ctx, &worlds) + releaseWorlds(worlds) + return nil +} + +func (r *TestController) getN(ctx http.Context) int { + n := ctx.Request().QueryInt(queryparam) + if n < 1 { + n = 1 + } else if n > 500 { + n = 500 + } + + return n +} + +func (r *TestController) getRand() int32 { + return rand.Int32N(worldcount) + 1 +} diff --git a/frameworks/Go/goravel/src/fiber/app/http/controllers/utils.go b/frameworks/Go/goravel/src/fiber/app/http/controllers/utils.go new file mode 100644 index 00000000000..b125edad3f3 --- /dev/null +++ b/frameworks/Go/goravel/src/fiber/app/http/controllers/utils.go @@ -0,0 +1,107 @@ +package controllers + +import ( + "fmt" + "sync" + "unsafe" + + "github.com/bytedance/sonic" + "github.com/goravel/framework/contracts/http" + "github.com/goravel/framework/facades" + + "goravel/app/models" +) + +const ( + queryparam = "q" + helloworld = "Hello, World!" + worldcount = 10000 + contentTypePlain = "text/plain; charset=utf-8" + contentTypeHtml = "text/html; charset=utf-8" + contentTypeJson = "application/json" +) + +type Message struct { + Message string `json:"message"` +} + +type Worlds []models.World + +var messagePool = sync.Pool{ + New: func() any { + return new(Message) + }, +} + +var worldPool = sync.Pool{ + New: func() any { + return new(models.World) + }, +} + +var worldsPool = sync.Pool{ + New: func() any { + return make(Worlds, 0, 500) + }, +} + +func acquireMessage() *Message { + return messagePool.Get().(*Message) +} + +func releaseMessage(m *Message) { + m.Message = "" + messagePool.Put(m) +} + +func acquireWorld() *models.World { + return worldPool.Get().(*models.World) +} + +func releaseWorld(w *models.World) { + w.ID = 0 + w.RandomNumber = 0 + worldPool.Put(w) +} + +func acquireWorlds() Worlds { + return worldsPool.Get().(Worlds) +} + +func releaseWorlds(w Worlds) { + w = w[:0] + worldsPool.Put(w) +} + +func str2bytes(s string) []byte { + return unsafe.Slice(unsafe.StringData(s), len(s)) +} + +func initCache() { + worlds := acquireWorlds() + defer releaseWorlds(worlds) + + if err := facades.Orm().Query().Get(&worlds); err != nil { + panic(fmt.Sprintf("Failed to init cached Worlds: %v", err)) + } + + facades.Cache().Forever("worlds", worlds) +} + +func JSON(ctx http.Context, data any) { + ctx.Response().Header("Server", "Goravel") + ctx.Response().Header("Content-Type", contentTypeJson) + bytes, _ := sonic.Marshal(data) + _, _ = ctx.Response().Writer().Write(bytes) +} + +func Plaintext(ctx http.Context, data string) { + ctx.Response().Header("Server", "Goravel") + ctx.Response().Header("Content-Type", contentTypePlain) + _, _ = ctx.Response().Writer().Write(str2bytes(data)) +} + +func HTML(ctx http.Context) { + ctx.Response().Header("Server", "Goravel") + ctx.Response().Header("Content-Type", contentTypeHtml) +} diff --git a/frameworks/Go/goravel/src/fiber/app/models/world.go b/frameworks/Go/goravel/src/fiber/app/models/world.go new file mode 100644 index 00000000000..da724366273 --- /dev/null +++ b/frameworks/Go/goravel/src/fiber/app/models/world.go @@ -0,0 +1,10 @@ +package models + +type World struct { + ID int32 `gorm:"primaryKey" json:"id"` + RandomNumber int32 `gorm:"column:randomnumber" json:"randomNumber"` +} + +func (r *World) TableName() string { + return "World" +} diff --git a/frameworks/Go/goravel/src/fiber/app/providers/route_service_provider.go b/frameworks/Go/goravel/src/fiber/app/providers/route_service_provider.go new file mode 100644 index 00000000000..2e96015a24f --- /dev/null +++ b/frameworks/Go/goravel/src/fiber/app/providers/route_service_provider.go @@ -0,0 +1,16 @@ +package providers + +import ( + "github.com/goravel/framework/contracts/foundation" + + "goravel/routes" +) + +type RouteServiceProvider struct{} + +func (receiver *RouteServiceProvider) Register(app foundation.Application) { +} + +func (receiver *RouteServiceProvider) Boot(app foundation.Application) { + routes.Web() +} diff --git a/frameworks/Go/goravel/src/fiber/config/app.go b/frameworks/Go/goravel/src/fiber/config/app.go new file mode 100644 index 00000000000..3ab05123159 --- /dev/null +++ b/frameworks/Go/goravel/src/fiber/config/app.go @@ -0,0 +1,40 @@ +package config + +import ( + "github.com/goravel/fiber" + "github.com/goravel/framework/cache" + "github.com/goravel/framework/console" + "github.com/goravel/framework/contracts/foundation" + "github.com/goravel/framework/database" + "github.com/goravel/framework/facades" + "github.com/goravel/framework/http" + "github.com/goravel/framework/log" + "github.com/goravel/framework/route" + "github.com/goravel/framework/validation" + + "goravel/app/providers" +) + +// Boot Start all init methods of the current folder to bootstrap all config. +func Boot() {} + +func init() { + config := facades.Config() + config.Add("app", map[string]any{ + "name": "Goravel", + "env": "production", + "debug": false, + "key": config.Env("APP_KEY", ""), + "providers": []foundation.ServiceProvider{ + &log.ServiceProvider{}, + &console.ServiceProvider{}, + &database.ServiceProvider{}, + &cache.ServiceProvider{}, + &http.ServiceProvider{}, + &route.ServiceProvider{}, + &validation.ServiceProvider{}, + &providers.RouteServiceProvider{}, + &fiber.ServiceProvider{}, + }, + }) +} diff --git a/frameworks/Go/goravel/src/fiber/config/cache.go b/frameworks/Go/goravel/src/fiber/config/cache.go new file mode 100644 index 00000000000..3c638243c2c --- /dev/null +++ b/frameworks/Go/goravel/src/fiber/config/cache.go @@ -0,0 +1,18 @@ +package config + +import ( + "github.com/goravel/framework/facades" +) + +func init() { + config := facades.Config() + config.Add("cache", map[string]any{ + "default": "memory", + "stores": map[string]any{ + "memory": map[string]any{ + "driver": "memory", + }, + }, + "prefix": "goravel_cache", + }) +} diff --git a/frameworks/Go/goravel/src/fiber/config/database.go b/frameworks/Go/goravel/src/fiber/config/database.go new file mode 100644 index 00000000000..e1b1eb3272a --- /dev/null +++ b/frameworks/Go/goravel/src/fiber/config/database.go @@ -0,0 +1,32 @@ +package config + +import ( + "github.com/goravel/framework/facades" +) + +func init() { + config := facades.Config() + config.Add("database", map[string]any{ + "default": "postgresql", + "connections": map[string]any{ + "postgresql": map[string]any{ + "driver": "postgresql", + "host": config.Env("DB_HOST", "tfb-database"), + "port": config.Env("DB_PORT", 5432), + "database": config.Env("DB_DATABASE", "hello_world"), + "username": config.Env("DB_USERNAME", "benchmarkdbuser"), + "password": config.Env("DB_PASSWORD", "benchmarkdbpass"), + "sslmode": "disable", + "timezone": "UTC", + "prefix": "", + "singular": true, + }, + }, + "pool": map[string]any{ + "max_idle_conns": 100, + "max_open_conns": 2000, + "conn_max_idletime": 3600, + "conn_max_lifetime": 3600, + }, + }) +} diff --git a/frameworks/Go/goravel/src/fiber/config/http.go b/frameworks/Go/goravel/src/fiber/config/http.go new file mode 100644 index 00000000000..3d48d689691 --- /dev/null +++ b/frameworks/Go/goravel/src/fiber/config/http.go @@ -0,0 +1,26 @@ +package config + +import ( + fiberfacades "github.com/goravel/fiber/facades" + "github.com/goravel/framework/contracts/route" + "github.com/goravel/framework/facades" +) + +func init() { + config := facades.Config() + config.Add("http", map[string]any{ + "default": "fiber", + "drivers": map[string]any{ + "fiber": map[string]any{ + "prefork": true, + "body_limit": 4096, + "header_limit": 4096, + "route": func() (route.Route, error) { + return fiberfacades.Route("fiber"), nil + }, + }, + }, + "host": "", + "port": "8080", + }) +} diff --git a/frameworks/Go/goravel/src/fiber/config/json.go b/frameworks/Go/goravel/src/fiber/config/json.go new file mode 100644 index 00000000000..2b2e1af3f80 --- /dev/null +++ b/frameworks/Go/goravel/src/fiber/config/json.go @@ -0,0 +1,31 @@ +package config + +import ( + "github.com/bytedance/sonic" + "github.com/goravel/framework/contracts/foundation" + "github.com/goravel/framework/facades" +) + +func init() { + facades.App().SetJson(NewJson()) +} + +type Json struct { + marshal func(any) ([]byte, error) + unmarshal func([]byte, any) error +} + +func NewJson() foundation.Json { + return &Json{ + marshal: sonic.Marshal, + unmarshal: sonic.Unmarshal, + } +} + +func (j *Json) Marshal(v any) ([]byte, error) { + return j.marshal(v) +} + +func (j *Json) Unmarshal(data []byte, v any) error { + return j.unmarshal(data, v) +} diff --git a/frameworks/Go/goravel/src/fiber/go.mod b/frameworks/Go/goravel/src/fiber/go.mod new file mode 100644 index 00000000000..e285c0106e3 --- /dev/null +++ b/frameworks/Go/goravel/src/fiber/go.mod @@ -0,0 +1,191 @@ +module goravel + +go 1.22 + +require ( + github.com/bytedance/sonic v1.11.9 + github.com/gofiber/fiber/v2 v2.52.4 + github.com/gofiber/template/html/v2 v2.1.1 + github.com/goravel/fiber v1.2.1 + github.com/goravel/framework v1.14.1 + github.com/valyala/quicktemplate v1.7.0 +) + +require ( + atomicgo.dev/cursor v0.2.0 // indirect + atomicgo.dev/keyboard v0.2.9 // indirect + atomicgo.dev/schedule v0.1.0 // indirect + cloud.google.com/go v0.112.1 // indirect + cloud.google.com/go/compute v1.25.1 // indirect + cloud.google.com/go/compute/metadata v0.2.3 // indirect + cloud.google.com/go/iam v1.1.6 // indirect + cloud.google.com/go/pubsub v1.36.1 // indirect + filippo.io/edwards25519 v1.1.0 // indirect + github.com/Azure/go-autorest v14.2.0+incompatible // indirect + github.com/Azure/go-autorest/autorest/adal v0.9.16 // indirect + github.com/Azure/go-autorest/autorest/date v0.3.0 // indirect + github.com/Azure/go-autorest/logger v0.2.1 // indirect + github.com/Azure/go-autorest/tracing v0.6.0 // indirect + github.com/RichardKnop/logging v0.0.0-20190827224416-1a693bdd4fae // indirect + github.com/RichardKnop/machinery/v2 v2.0.13 // indirect + github.com/andybalholm/brotli v1.1.0 // indirect + github.com/atotto/clipboard v0.1.4 // indirect + github.com/aws/aws-sdk-go v1.49.6 // indirect + github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect + github.com/bytedance/sonic/loader v0.1.1 // indirect + github.com/catppuccin/go v0.2.0 // indirect + github.com/cespare/xxhash/v2 v2.2.0 // indirect + github.com/charmbracelet/bubbles v0.18.0 // indirect + github.com/charmbracelet/bubbletea v0.26.3 // indirect + github.com/charmbracelet/huh v0.4.2 // indirect + github.com/charmbracelet/huh/spinner v0.0.0-20240508140610-13957916abf0 // indirect + github.com/charmbracelet/lipgloss v0.11.0 // indirect + github.com/charmbracelet/x/ansi v0.1.1 // indirect + github.com/charmbracelet/x/exp/strings v0.0.0-20240524151031-ff83003bf67a // indirect + github.com/charmbracelet/x/input v0.1.1 // indirect + github.com/charmbracelet/x/term v0.1.1 // indirect + github.com/charmbracelet/x/windows v0.1.2 // indirect + github.com/cloudwego/base64x v0.1.4 // indirect + github.com/cloudwego/iasm v0.2.0 // indirect + github.com/containerd/console v1.0.4-0.20230313162750-1ae8d489ac81 // indirect + github.com/cpuguy83/go-md2man/v2 v2.0.4 // indirect + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect + github.com/dustin/go-humanize v1.0.1 // indirect + github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f // indirect + github.com/felixge/httpsnoop v1.0.4 // indirect + github.com/fsnotify/fsnotify v1.7.0 // indirect + github.com/gabriel-vasile/mimetype v1.4.4 // indirect + github.com/glebarez/go-sqlite v1.22.0 // indirect + github.com/glebarez/sqlite v1.11.0 // indirect + github.com/go-logr/logr v1.4.1 // indirect + github.com/go-logr/stdr v1.2.2 // indirect + github.com/go-redsync/redsync/v4 v4.8.1 // indirect + github.com/go-sql-driver/mysql v1.8.1 // indirect + github.com/go-stack/stack v1.8.0 // indirect + github.com/gofiber/template v1.8.3 // indirect + github.com/gofiber/utils v1.1.0 // indirect + github.com/golang-jwt/jwt/v4 v4.5.0 // indirect + github.com/golang-jwt/jwt/v5 v5.2.1 // indirect + github.com/golang-migrate/migrate/v4 v4.17.1 // indirect + github.com/golang-module/carbon/v2 v2.3.12 // indirect + github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 // indirect + github.com/golang-sql/sqlexp v0.1.0 // indirect + github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect + github.com/golang/protobuf v1.5.4 // indirect + github.com/golang/snappy v0.0.4 // indirect + github.com/gomodule/redigo v2.0.0+incompatible // indirect + github.com/google/s2a-go v0.1.7 // indirect + github.com/google/uuid v1.6.0 // indirect + github.com/google/wire v0.6.0 // indirect + github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect + github.com/googleapis/gax-go/v2 v2.12.3 // indirect + github.com/gookit/color v1.5.4 // indirect + github.com/gookit/filter v1.2.1 // indirect + github.com/gookit/goutil v0.6.15 // indirect + github.com/gookit/validate v1.5.2 // indirect + github.com/goravel/file-rotatelogs/v2 v2.4.2 // indirect + github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 // indirect + github.com/hashicorp/errwrap v1.1.0 // indirect + github.com/hashicorp/go-multierror v1.1.1 // indirect + github.com/hashicorp/hcl v1.0.0 // indirect + github.com/jackc/pgpassfile v1.0.0 // indirect + github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect + github.com/jackc/pgx/v5 v5.5.4 // indirect + github.com/jackc/puddle/v2 v2.2.1 // indirect + github.com/jinzhu/inflection v1.0.0 // indirect + github.com/jinzhu/now v1.1.5 // indirect + github.com/jmespath/go-jmespath v0.4.0 // indirect + github.com/kelseyhightower/envconfig v1.4.0 // indirect + github.com/klauspost/compress v1.17.9 // indirect + github.com/klauspost/cpuid/v2 v2.2.7 // indirect + github.com/lib/pq v1.10.9 // indirect + github.com/lithammer/fuzzysearch v1.1.8 // indirect + github.com/lucasb-eyer/go-colorful v1.2.0 // indirect + github.com/magiconair/properties v1.8.7 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect + github.com/mattn/go-localereader v0.0.1 // indirect + github.com/mattn/go-runewidth v0.0.15 // indirect + github.com/microsoft/go-mssqldb v1.6.0 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 // indirect + github.com/muesli/cancelreader v0.2.2 // indirect + github.com/muesli/termenv v0.15.2 // indirect + github.com/opentracing/opentracing-go v1.2.0 // indirect + github.com/patrickmn/go-cache v2.1.0+incompatible // indirect + github.com/pelletier/go-toml/v2 v2.2.2 // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect + github.com/pterm/pterm v0.12.79 // indirect + github.com/rabbitmq/amqp091-go v1.9.0 // indirect + github.com/redis/go-redis/v9 v9.5.3 // indirect + github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect + github.com/rifflock/lfshook v0.0.0-20180920164130-b9218ef580f5 // indirect + github.com/rivo/uniseg v0.4.7 // indirect + github.com/robfig/cron/v3 v3.0.1 // indirect + github.com/rogpeppe/go-internal v1.11.0 // indirect + github.com/rotisserie/eris v0.5.4 // indirect + github.com/russross/blackfriday/v2 v2.1.0 // indirect + github.com/sagikazarmark/locafero v0.4.0 // indirect + github.com/sagikazarmark/slog-shim v0.1.0 // indirect + github.com/savioxavier/termlink v1.3.0 // indirect + github.com/sirupsen/logrus v1.9.3 // indirect + github.com/sourcegraph/conc v0.3.0 // indirect + github.com/spf13/afero v1.11.0 // indirect + github.com/spf13/cast v1.6.0 // indirect + github.com/spf13/pflag v1.0.5 // indirect + github.com/spf13/viper v1.19.0 // indirect + github.com/stretchr/objx v0.5.2 // indirect + github.com/stretchr/testify v1.9.0 // indirect + github.com/subosito/gotenv v1.6.0 // indirect + github.com/twitchyliquid64/golang-asm v0.15.1 // indirect + github.com/urfave/cli/v2 v2.27.2 // indirect + github.com/valyala/bytebufferpool v1.0.0 // indirect + github.com/valyala/fasthttp v1.55.0 // indirect + github.com/valyala/tcplisten v1.0.0 // indirect + github.com/xdg-go/pbkdf2 v1.0.0 // indirect + github.com/xdg-go/scram v1.1.1 // indirect + github.com/xdg-go/stringprep v1.0.3 // indirect + github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect + github.com/xrash/smetrics v0.0.0-20240312152122-5f08fbb34913 // indirect + github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d // indirect + go.mongodb.org/mongo-driver v1.7.5 // indirect + go.opencensus.io v0.24.0 // indirect + go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0 // indirect + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 // indirect + go.opentelemetry.io/otel v1.24.0 // indirect + go.opentelemetry.io/otel/metric v1.24.0 // indirect + go.opentelemetry.io/otel/trace v1.24.0 // indirect + go.uber.org/atomic v1.11.0 // indirect + go.uber.org/multierr v1.9.0 // indirect + golang.org/x/arch v0.0.0-20210923205945-b76863e36670 // indirect + golang.org/x/crypto v0.24.0 // indirect + golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect + golang.org/x/net v0.26.0 // indirect + golang.org/x/oauth2 v0.18.0 // indirect + golang.org/x/sync v0.7.0 // indirect + golang.org/x/sys v0.21.0 // indirect + golang.org/x/term v0.21.0 // indirect + golang.org/x/text v0.16.0 // indirect + golang.org/x/time v0.5.0 // indirect + google.golang.org/api v0.171.0 // indirect + google.golang.org/appengine v1.6.8 // indirect + google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20240318140521-94a12d6c2237 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237 // indirect + google.golang.org/grpc v1.64.0 // indirect + google.golang.org/protobuf v1.34.1 // indirect + gopkg.in/ini.v1 v1.67.0 // indirect + gopkg.in/yaml.v2 v2.4.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect + gorm.io/driver/mysql v1.5.6 // indirect + gorm.io/driver/postgres v1.5.7 // indirect + gorm.io/driver/sqlserver v1.5.3 // indirect + gorm.io/gorm v1.25.10 // indirect + gorm.io/plugin/dbresolver v1.5.1 // indirect + modernc.org/libc v1.37.6 // indirect + modernc.org/mathutil v1.6.0 // indirect + modernc.org/memory v1.7.2 // indirect + modernc.org/sqlite v1.28.0 // indirect +) diff --git a/frameworks/Go/goravel/src/fiber/go.sum b/frameworks/Go/goravel/src/fiber/go.sum new file mode 100644 index 00000000000..942ea9c3e7f --- /dev/null +++ b/frameworks/Go/goravel/src/fiber/go.sum @@ -0,0 +1,1170 @@ +atomicgo.dev/assert v0.0.2 h1:FiKeMiZSgRrZsPo9qn/7vmr7mCsh5SZyXY4YGYiYwrg= +atomicgo.dev/assert v0.0.2/go.mod h1:ut4NcI3QDdJtlmAxQULOmA13Gz6e2DWbSAS8RUOmNYQ= +atomicgo.dev/cursor v0.2.0 h1:H6XN5alUJ52FZZUkI7AlJbUc1aW38GWZalpYRPpoPOw= +atomicgo.dev/cursor v0.2.0/go.mod h1:Lr4ZJB3U7DfPPOkbH7/6TOtJ4vFGHlgj1nc+n900IpU= +atomicgo.dev/keyboard v0.2.9 h1:tOsIid3nlPLZ3lwgG8KZMp/SFmr7P0ssEN5JUsm78K8= +atomicgo.dev/keyboard v0.2.9/go.mod h1:BC4w9g00XkxH/f1HXhW2sXmJFOCWbKn9xrOunSFtExQ= +atomicgo.dev/schedule v0.1.0 h1:nTthAbhZS5YZmgYbb2+DH8uQIZcTlIrd4eYr3UQxEjs= +atomicgo.dev/schedule v0.1.0/go.mod h1:xeUa3oAkiuHYh8bKiQBRojqAMq3PXXbJujjb0hw8pEU= +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= +cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= +cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= +cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= +cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= +cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= +cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= +cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= +cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= +cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= +cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= +cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= +cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= +cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= +cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= +cloud.google.com/go v0.75.0/go.mod h1:VGuuCn7PG0dwsd5XPVm2Mm3wlh3EL55/79EKB6hlPTY= +cloud.google.com/go v0.112.1 h1:uJSeirPke5UNZHIb4SxfZklVSiWWVqW4oXlETwZziwM= +cloud.google.com/go v0.112.1/go.mod h1:+Vbu+Y1UU+I1rjmzeMOb/8RfkKJK2Gyxi1X6jJCZLo4= +cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= +cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= +cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= +cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= +cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= +cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= +cloud.google.com/go/compute v1.25.1 h1:ZRpHJedLtTpKgr3RV1Fx23NuaAEN1Zfx9hw1u4aJdjU= +cloud.google.com/go/compute v1.25.1/go.mod h1:oopOIR53ly6viBYxaDhBfJwzUAxf1zE//uf3IB011ls= +cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY= +cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= +cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= +cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= +cloud.google.com/go/iam v1.1.6 h1:bEa06k05IO4f4uJonbB5iAgKTPpABy1ayxaIZV/GHVc= +cloud.google.com/go/iam v1.1.6/go.mod h1:O0zxdPeGBoFdWW3HWmBxJsk0pfvNM/p/qa82rWOGTwI= +cloud.google.com/go/kms v1.15.7 h1:7caV9K3yIxvlQPAcaFffhlT7d1qpxjB1wHBtjWa13SM= +cloud.google.com/go/kms v1.15.7/go.mod h1:ub54lbsa6tDkUwnu4W7Yt1aAIFLnspgh0kPGToDukeI= +cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= +cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= +cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= +cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= +cloud.google.com/go/pubsub v1.10.0/go.mod h1:eNpTrkOy7dCpkNyaSNetMa6udbgecJMd0ZsTJS/cuNo= +cloud.google.com/go/pubsub v1.36.1 h1:dfEPuGCHGbWUhaMCTHUFjfroILEkx55iUmKBZTP5f+Y= +cloud.google.com/go/pubsub v1.36.1/go.mod h1:iYjCa9EzWOoBiTdd4ps7QoMtMln5NwaZQpK1hbRfBDE= +cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= +cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= +cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= +cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= +cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= +dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= +filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.4.0/go.mod h1:ON4tFdPTwRcgWEaVDrN3584Ef+b7GgSJaXxe5fW9t4M= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.6.0/go.mod h1:bjGvMhVMb+EEm3VRNQawDMUyMMjo+S5ewNjflkep/0Q= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.6.1/go.mod h1:bjGvMhVMb+EEm3VRNQawDMUyMMjo+S5ewNjflkep/0Q= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.7.1 h1:/iHxaJhsFr0+xVFfbMr5vxz848jyiWuIEDhYq3y5odY= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.7.1/go.mod h1:bjGvMhVMb+EEm3VRNQawDMUyMMjo+S5ewNjflkep/0Q= +github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.3.0 h1:vcYCAze6p19qBW7MhZybIsqD8sMV8js0NyQM8JDnVtg= +github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.3.0/go.mod h1:OQeznEEkTZ9OrhHJoDD8ZDq51FHgXjqtP9z6bEwBq9U= +github.com/Azure/azure-sdk-for-go/sdk/internal v1.1.2/go.mod h1:eWRD7oawr1Mu1sLCawqVc0CUiF43ia3qQMxLscsKQ9w= +github.com/Azure/azure-sdk-for-go/sdk/internal v1.2.0/go.mod h1:eWRD7oawr1Mu1sLCawqVc0CUiF43ia3qQMxLscsKQ9w= +github.com/Azure/azure-sdk-for-go/sdk/internal v1.3.0 h1:sXr+ck84g/ZlZUOZiNELInmMgOsuGwdjjVkEIde0OtY= +github.com/Azure/azure-sdk-for-go/sdk/internal v1.3.0/go.mod h1:okt5dMMTOFjX/aovMlrjvvXoPMBVSPzk9185BT0+eZM= +github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azkeys v1.0.0 h1:yfJe15aSwEQ6Oo6J+gdfdulPNoZ3TEhmbhLIoxZcA+U= +github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azkeys v1.0.0/go.mod h1:Q28U+75mpCaSCDowNEmhIo/rmgdkqmkmzI7N6TGR4UY= +github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v0.8.0 h1:T028gtTPiYt/RMUfs8nVsAL7FDQrfLlrm/NnRG/zcC4= +github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v0.8.0/go.mod h1:cw4zVQgBby0Z5f2v0itn6se2dDP17nTjbZFXW5uPyHA= +github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25UVaW/CKtUDjefjrs0SPonmDGUVOYP0= +github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= +github.com/Azure/go-autorest v14.2.0+incompatible h1:V5VMDjClD3GiElqLWO7mz2MxNAK/vTfRHdAubSIPRgs= +github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= +github.com/Azure/go-autorest/autorest/adal v0.9.16 h1:P8An8Z9rH1ldbOLdFpxYorgOt2sywL9V24dAwWHPuGc= +github.com/Azure/go-autorest/autorest/adal v0.9.16/go.mod h1:tGMin8I49Yij6AQ+rvV+Xa/zwxYQB5hmsd6DkfAx2+A= +github.com/Azure/go-autorest/autorest/date v0.3.0 h1:7gUk1U5M/CQbp9WoqinNzJar+8KY+LPI6wiWrP/myHw= +github.com/Azure/go-autorest/autorest/date v0.3.0/go.mod h1:BI0uouVdmngYNUzGWeSYnokU+TrmwEsOqdt8Y6sso74= +github.com/Azure/go-autorest/autorest/mocks v0.4.1 h1:K0laFcLE6VLTOwNgSxaGbUcLPuGXlNkbVvq4cW4nIHk= +github.com/Azure/go-autorest/autorest/mocks v0.4.1/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k= +github.com/Azure/go-autorest/logger v0.2.1 h1:IG7i4p/mDa2Ce4TRyAO8IHnVhAVF3RFU+ZtXWSmf4Tg= +github.com/Azure/go-autorest/logger v0.2.1/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8= +github.com/Azure/go-autorest/tracing v0.6.0 h1:TYi4+3m5t6K48TGI9AUdb+IzbnSxvnvUMfuitfgcfuo= +github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU= +github.com/AzureAD/microsoft-authentication-library-for-go v1.0.0/go.mod h1:kgDmCTgBzIEPFElEF+FK0SdjAor06dRq2Go927dnQ6o= +github.com/AzureAD/microsoft-authentication-library-for-go v1.1.0 h1:HCc0+LpPfpCKs6LGGLAhwBARt9632unrVcI6i8s/8os= +github.com/AzureAD/microsoft-authentication-library-for-go v1.1.0/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/MarvinJWendt/testza v0.1.0/go.mod h1:7AxNvlfeHP7Z/hDQ5JtE3OKYT3XFUeLCDE2DQninSqs= +github.com/MarvinJWendt/testza v0.2.1/go.mod h1:God7bhG8n6uQxwdScay+gjm9/LnO4D3kkcZX4hv9Rp8= +github.com/MarvinJWendt/testza v0.2.8/go.mod h1:nwIcjmr0Zz+Rcwfh3/4UhBp7ePKVhuBExvZqnKYWlII= +github.com/MarvinJWendt/testza v0.2.10/go.mod h1:pd+VWsoGUiFtq+hRKSU1Bktnn+DMCSrDrXDpX2bG66k= +github.com/MarvinJWendt/testza v0.2.12/go.mod h1:JOIegYyV7rX+7VZ9r77L/eH6CfJHHzXjB69adAhzZkI= +github.com/MarvinJWendt/testza v0.3.0/go.mod h1:eFcL4I0idjtIx8P9C6KkAuLgATNKpX4/2oUqKc6bF2c= +github.com/MarvinJWendt/testza v0.4.2/go.mod h1:mSdhXiKH8sg/gQehJ63bINcCKp7RtYewEjXsvsVUPbE= +github.com/MarvinJWendt/testza v0.5.2 h1:53KDo64C1z/h/d/stCYCPY69bt/OSwjq5KpFNwi+zB4= +github.com/MarvinJWendt/testza v0.5.2/go.mod h1:xu53QFE5sCdjtMCKk8YMQ2MnymimEctc4n3EjyIYvEY= +github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow= +github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= +github.com/RichardKnop/logging v0.0.0-20190827224416-1a693bdd4fae h1:DcFpTQBYQ9Ct2d6sC7ol0/ynxc2pO1cpGUM+f4t5adg= +github.com/RichardKnop/logging v0.0.0-20190827224416-1a693bdd4fae/go.mod h1:rJJ84PyA/Wlmw1hO+xTzV2wsSUon6J5ktg0g8BF2PuU= +github.com/RichardKnop/machinery/v2 v2.0.13 h1:uo9htg+qNBi7UeUK3jcTBl3vTO/vvLKGaOdCOKePl50= +github.com/RichardKnop/machinery/v2 v2.0.13/go.mod h1:Yc2X/QRm9rRfAjB+93NGR+kSUqtnqqs8kME4L+TKKiw= +github.com/andybalholm/brotli v1.0.2/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y= +github.com/andybalholm/brotli v1.0.3/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= +github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1U3M= +github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY= +github.com/atomicgo/cursor v0.0.1/go.mod h1:cBON2QmmrysudxNBFthvMtN32r3jxVRIvzkUiF/RuIk= +github.com/atotto/clipboard v0.1.4 h1:EH0zSVneZPSuFR11BlR9YppQTVDbh5+16AmcJi4g1z4= +github.com/atotto/clipboard v0.1.4/go.mod h1:ZY9tmq7sm5xIbd9bOK4onWV4S6X0u6GY7Vn0Yu86PYI= +github.com/aws/aws-sdk-go v1.34.28/go.mod h1:H7NKnBqNVzoTJpGfLrQkkD+ytBA93eiDYi/+8rV9s48= +github.com/aws/aws-sdk-go v1.37.16/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= +github.com/aws/aws-sdk-go v1.49.6 h1:yNldzF5kzLBRvKlKz1S0bkvc2+04R1kt13KfBWQBfFA= +github.com/aws/aws-sdk-go v1.49.6/go.mod h1:LF8svs817+Nz+DmiMQKTO3ubZ/6IaTpq3TjupRn3Eqk= +github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k= +github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8= +github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= +github.com/bradfitz/gomemcache v0.0.0-20190913173617-a41fca850d0b/go.mod h1:H0wQNHz2YrLsuXOZozoeDmnHXkNCRmMW0gwFWDfEZDA= +github.com/brianvoe/gofakeit/v6 v6.28.0 h1:Xib46XXuQfmlLS2EXRuJpqcw8St6qSZz75OUo0tgAW4= +github.com/brianvoe/gofakeit/v6 v6.28.0/go.mod h1:Xj58BMSnFqcn/fAQeSK+/PLtC5kSb7FJIq4JyGa8vEs= +github.com/bsm/ginkgo/v2 v2.5.0/go.mod h1:AiKlXPm7ItEHNc/2+OkrNG4E0ITzojb9/xWzvQ9XZ9w= +github.com/bsm/ginkgo/v2 v2.7.0/go.mod h1:AiKlXPm7ItEHNc/2+OkrNG4E0ITzojb9/xWzvQ9XZ9w= +github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs= +github.com/bsm/ginkgo/v2 v2.12.0/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdbAV9g4c= +github.com/bsm/gomega v1.20.0/go.mod h1:JifAceMQ4crZIWYUKrlGcmbN3bqHogVTADMD2ATsbwk= +github.com/bsm/gomega v1.26.0/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0= +github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA= +github.com/bsm/gomega v1.27.10/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0= +github.com/bytedance/sonic v1.11.9 h1:LFHENlIY/SLzDWverzdOvgMztTxcfcF+cqNsz9pK5zg= +github.com/bytedance/sonic v1.11.9/go.mod h1:LysEHSvpvDySVdC2f87zGWf6CIKJcAvqab1ZaiQtds4= +github.com/bytedance/sonic/loader v0.1.1 h1:c+e5Pt1k/cy5wMveRDyk2X4B9hF4g7an8N3zCYjJFNM= +github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU= +github.com/catppuccin/go v0.2.0 h1:ktBeIrIP42b/8FGiScP9sgrWOss3lw0Z5SktRoithGA= +github.com/catppuccin/go v0.2.0/go.mod h1:8IHJuMGaUUjQM82qBrGNBv7LFq6JI3NnQCF6MOlZjpc= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= +github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/charmbracelet/bubbles v0.18.0 h1:PYv1A036luoBGroX6VWjQIE9Syf2Wby2oOl/39KLfy0= +github.com/charmbracelet/bubbles v0.18.0/go.mod h1:08qhZhtIwzgrtBjAcJnij1t1H0ZRjwHyGsy6AL11PSw= +github.com/charmbracelet/bubbletea v0.26.3 h1:iXyGvI+FfOWqkB2V07m1DF3xxQijxjY2j8PqiXYqasg= +github.com/charmbracelet/bubbletea v0.26.3/go.mod h1:bpZHfDHTYJC5g+FBK+ptJRCQotRC+Dhh3AoMxa/2+3Q= +github.com/charmbracelet/huh v0.4.2 h1:5wLkwrA58XDAfEZsJzNQlfJ+K8N9+wYwvR5FOM7jXFM= +github.com/charmbracelet/huh v0.4.2/go.mod h1:g9OXBgtY3zRV4ahnVih9bZE+1yGYN+y2C9Q6L2P+WM0= +github.com/charmbracelet/huh/spinner v0.0.0-20240508140610-13957916abf0 h1:79JTuYRirtyCn9ac6rzPt5AQKtBDFc1gKxpw0wBrI+Y= +github.com/charmbracelet/huh/spinner v0.0.0-20240508140610-13957916abf0/go.mod h1:Zxt9FH6togK9kY71pRJGtmyNkJ1eIWdK1gRaXrS/FKA= +github.com/charmbracelet/lipgloss v0.11.0 h1:UoAcbQ6Qml8hDwSWs0Y1cB5TEQuZkDPH/ZqwWWYTG4g= +github.com/charmbracelet/lipgloss v0.11.0/go.mod h1:1UdRTH9gYgpcdNN5oBtjbu/IzNKtzVtb7sqN1t9LNn8= +github.com/charmbracelet/x/ansi v0.1.1 h1:CGAduulr6egay/YVbGc8Hsu8deMg1xZ/bkaXTPi1JDk= +github.com/charmbracelet/x/ansi v0.1.1/go.mod h1:dk73KoMTT5AX5BsX0KrqhsTqAnhZZoCBjs7dGWp4Ktw= +github.com/charmbracelet/x/exp/strings v0.0.0-20240524151031-ff83003bf67a h1:lOpqe2UvPmlln41DGoii7wlSZ/q8qGIon5JJ8Biu46I= +github.com/charmbracelet/x/exp/strings v0.0.0-20240524151031-ff83003bf67a/go.mod h1:pBhA0ybfXv6hDjQUZ7hk1lVxBiUbupdw5R31yPUViVQ= +github.com/charmbracelet/x/exp/term v0.0.0-20240524151031-ff83003bf67a h1:k/s6UoOSVynWiw7PlclyGO2VdVs5ZLbMIHiGp4shFZE= +github.com/charmbracelet/x/exp/term v0.0.0-20240524151031-ff83003bf67a/go.mod h1:YBotIGhfoWhHDlnUpJMkjebGV2pdGRCn1Y4/Nk/vVcU= +github.com/charmbracelet/x/input v0.1.1 h1:YDOJaTUKCqtGnq9PHzx3pkkl4pXDOANUHmhH3DqMtM4= +github.com/charmbracelet/x/input v0.1.1/go.mod h1:jvdTVUnNWj/RD6hjC4FsoB0SeZCJ2ZBkiuFP9zXvZI0= +github.com/charmbracelet/x/term v0.1.1 h1:3cosVAiPOig+EV4X9U+3LDgtwwAoEzJjNdwbXDjF6yI= +github.com/charmbracelet/x/term v0.1.1/go.mod h1:wB1fHt5ECsu3mXYusyzcngVWWlu1KKUmmLhfgr/Flxw= +github.com/charmbracelet/x/windows v0.1.2 h1:Iumiwq2G+BRmgoayww/qfcvof7W/3uLoelhxojXlRWg= +github.com/charmbracelet/x/windows v0.1.2/go.mod h1:GLEO/l+lizvFDBPLIOk+49gdX49L9YWMB5t+DZd0jkQ= +github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cloudwego/base64x v0.1.4 h1:jwCgWpFanWmN8xoIUHa2rtzmkd5J2plF/dnLS6Xd/0Y= +github.com/cloudwego/base64x v0.1.4/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w= +github.com/cloudwego/iasm v0.2.0 h1:1KNIy1I1H9hNNFEEH3DVnI4UujN+1zjpuk6gwHLTssg= +github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY= +github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= +github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/containerd/console v1.0.3/go.mod h1:7LqA/THxQ86k76b8c/EMSiaJ3h1eZkMkXar0TQ1gf3U= +github.com/containerd/console v1.0.4-0.20230313162750-1ae8d489ac81 h1:q2hJAaP1k2wIvVRd/hEHD7lacgqrCPS+k8g1MndzfWY= +github.com/containerd/console v1.0.4-0.20230313162750-1ae8d489ac81/go.mod h1:YynlIjWYF8myEu6sdkwKIvGQq+cOckRm6So2avqoYAk= +github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/cpuguy83/go-md2man/v2 v2.0.4 h1:wfIWP927BUkWJb2NmU/kNDYIBTh/ziUX91+lVfRxZq4= +github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= +github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= +github.com/dhui/dktest v0.4.1 h1:/w+IWuDXVymg3IrRJCHHOkMK10m9aNVMOyD0X12YVTg= +github.com/dhui/dktest v0.4.1/go.mod h1:DdOqcUpL7vgyP4GlF3X3w7HbSlz8cEQzwewPveYEQbA= +github.com/dnaeon/go-vcr v1.1.0/go.mod h1:M7tiix8f0r6mKKJ3Yq/kqU1OYf3MnfmBWVbPx/yU9ko= +github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ= +github.com/docker/distribution v2.8.2+incompatible h1:T3de5rq0dB1j30rp0sA2rER+m322EBzniBPB6ZIzuh8= +github.com/docker/distribution v2.8.2+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= +github.com/docker/docker v24.0.9+incompatible h1:HPGzNmwfLZWdxHqK9/II92pyi1EpYKsAqcl4G0Of9v0= +github.com/docker/docker v24.0.9+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ= +github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= +github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= +github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= +github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= +github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= +github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= +github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f h1:Y/CXytFA4m6baUTXGLOoWe4PQhGxaX0KpnayAqC48p4= +github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f/go.mod h1:vw97MGsxSvLiUE2X8qFplwetxpGLQrlU1Q9AUEIzCaM= +github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= +github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= +github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= +github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= +github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= +github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= +github.com/gabriel-vasile/mimetype v1.4.4 h1:QjV6pZ7/XZ7ryI2KuyeEDE8wnh7fHP9YnQy+R0LnH8I= +github.com/gabriel-vasile/mimetype v1.4.4/go.mod h1:JwLei5XPtWdGiMFB5Pjle1oEeoSeEuJfJE+TtfvdB/s= +github.com/glebarez/go-sqlite v1.22.0 h1:uAcMJhaA6r3LHMTFgP0SifzgXg46yJkgxqyuyec+ruQ= +github.com/glebarez/go-sqlite v1.22.0/go.mod h1:PlBIdHe0+aUEFn+r2/uthrWq4FxbzugL0L8Li6yQJbc= +github.com/glebarez/sqlite v1.11.0 h1:wSG0irqzP6VurnMEpFGer5Li19RpIRi2qvQz++w0GMw= +github.com/glebarez/sqlite v1.11.0/go.mod h1:h8/o8j5wiAsqSPoWELDUdJXhjAhsVliSn7bWZjOhrgQ= +github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= +github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= +github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ= +github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= +github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= +github.com/go-redis/redis v6.15.9+incompatible h1:K0pv1D7EQUjfyoMql+r/jZqCLizCGKFlFgcHWWmHQjg= +github.com/go-redis/redis v6.15.9+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA= +github.com/go-redis/redis/v7 v7.4.0 h1:7obg6wUoj05T0EpY0o8B59S9w5yeMWql7sw2kwNW1x4= +github.com/go-redis/redis/v7 v7.4.0/go.mod h1:JDNMw23GTyLNC4GZu9njt15ctBQVn7xjRfnwdHj/Dcg= +github.com/go-redis/redis/v8 v8.11.4/go.mod h1:2Z2wHZXdQpCDXEGzqMockDpNyYvi2l4Pxt6RJr792+w= +github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC0oI= +github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo= +github.com/go-redsync/redsync/v4 v4.8.1 h1:rq2RvdTI0obznMdxKUWGdmmulo7lS9yCzb8fgDKOlbM= +github.com/go-redsync/redsync/v4 v4.8.1/go.mod h1:LmUAsQuQxhzZAoGY7JS6+dNhNmZyonMZiiEDY9plotM= +github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= +github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= +github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI= +github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y= +github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg= +github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= +github.com/gobuffalo/attrs v0.0.0-20190224210810-a9411de4debd/go.mod h1:4duuawTqi2wkkpB4ePgWMaai6/Kc6WEz83bhFwpHzj0= +github.com/gobuffalo/depgen v0.0.0-20190329151759-d478694a28d3/go.mod h1:3STtPUQYuzV0gBVOY3vy6CfMm/ljR4pABfrTeHNLHUY= +github.com/gobuffalo/depgen v0.1.0/go.mod h1:+ifsuy7fhi15RWncXQQKjWS9JPkdah5sZvtHc2RXGlg= +github.com/gobuffalo/envy v1.6.15/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI= +github.com/gobuffalo/envy v1.7.0/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI= +github.com/gobuffalo/flect v0.1.0/go.mod h1:d2ehjJqGOH/Kjqcoz+F7jHTBbmDb38yXA598Hb50EGs= +github.com/gobuffalo/flect v0.1.1/go.mod h1:8JCgGVbRjJhVgD6399mQr4fx5rRfGKVzFjbj6RE/9UI= +github.com/gobuffalo/flect v0.1.3/go.mod h1:8JCgGVbRjJhVgD6399mQr4fx5rRfGKVzFjbj6RE/9UI= +github.com/gobuffalo/genny v0.0.0-20190329151137-27723ad26ef9/go.mod h1:rWs4Z12d1Zbf19rlsn0nurr75KqhYp52EAGGxTbBhNk= +github.com/gobuffalo/genny v0.0.0-20190403191548-3ca520ef0d9e/go.mod h1:80lIj3kVJWwOrXWWMRzzdhW3DsrdjILVil/SFKBzF28= +github.com/gobuffalo/genny v0.1.0/go.mod h1:XidbUqzak3lHdS//TPu2OgiFB+51Ur5f7CSnXZ/JDvo= +github.com/gobuffalo/genny v0.1.1/go.mod h1:5TExbEyY48pfunL4QSXxlDOmdsD44RRq4mVZ0Ex28Xk= +github.com/gobuffalo/gitgen v0.0.0-20190315122116-cc086187d211/go.mod h1:vEHJk/E9DmhejeLeNt7UVvlSGv3ziL+djtTr3yyzcOw= +github.com/gobuffalo/gogen v0.0.0-20190315121717-8f38393713f5/go.mod h1:V9QVDIxsgKNZs6L2IYiGR8datgMhB577vzTDqypH360= +github.com/gobuffalo/gogen v0.1.0/go.mod h1:8NTelM5qd8RZ15VjQTFkAW6qOMx5wBbW4dSCS3BY8gg= +github.com/gobuffalo/gogen v0.1.1/go.mod h1:y8iBtmHmGc4qa3urIyo1shvOD8JftTtfcKi+71xfDNE= +github.com/gobuffalo/logger v0.0.0-20190315122211-86e12af44bc2/go.mod h1:QdxcLw541hSGtBnhUc4gaNIXRjiDppFGaDqzbrBd3v8= +github.com/gobuffalo/mapi v1.0.1/go.mod h1:4VAGh89y6rVOvm5A8fKFxYG+wIW6LO1FMTG9hnKStFc= +github.com/gobuffalo/mapi v1.0.2/go.mod h1:4VAGh89y6rVOvm5A8fKFxYG+wIW6LO1FMTG9hnKStFc= +github.com/gobuffalo/packd v0.0.0-20190315124812-a385830c7fc0/go.mod h1:M2Juc+hhDXf/PnmBANFCqx4DM3wRbgDvnVWeG2RIxq4= +github.com/gobuffalo/packd v0.1.0/go.mod h1:M2Juc+hhDXf/PnmBANFCqx4DM3wRbgDvnVWeG2RIxq4= +github.com/gobuffalo/packr/v2 v2.0.9/go.mod h1:emmyGweYTm6Kdper+iywB6YK5YzuKchGtJQZ0Odn4pQ= +github.com/gobuffalo/packr/v2 v2.2.0/go.mod h1:CaAwI0GPIAv+5wKLtv8Afwl+Cm78K/I/VCm/3ptBN+0= +github.com/gobuffalo/syncx v0.0.0-20190224160051-33c29581e754/go.mod h1:HhnNqWY95UYwwW3uSASeV7vtgYkT2t16hJgV3AEPUpw= +github.com/gofiber/fiber/v2 v2.52.4 h1:P+T+4iK7VaqUsq2PALYEfBBo6bJZ4q3FP8cZ84EggTM= +github.com/gofiber/fiber/v2 v2.52.4/go.mod h1:KEOE+cXMhXG0zHc9d8+E38hoX+ZN7bhOtgeF2oT6jrQ= +github.com/gofiber/template v1.8.3 h1:hzHdvMwMo/T2kouz2pPCA0zGiLCeMnoGsQZBTSYgZxc= +github.com/gofiber/template v1.8.3/go.mod h1:bs/2n0pSNPOkRa5VJ8zTIvedcI/lEYxzV3+YPXdBvq8= +github.com/gofiber/template/html/v2 v2.1.1 h1:QEy3O3EBkvwDthy5bXVGUseOyO6ldJoiDxlF4+MJiV8= +github.com/gofiber/template/html/v2 v2.1.1/go.mod h1:2G0GHHOUx70C1LDncoBpe4T6maQbNa4x1CVNFW0wju0= +github.com/gofiber/utils v1.1.0 h1:vdEBpn7AzIUJRhe+CiTOJdUcTg4Q9RK+pEa0KPbLdrM= +github.com/gofiber/utils v1.1.0/go.mod h1:poZpsnhBykfnY1Mc0KeEa6mSHrS3dV0+oBWyeQmb2e0= +github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang-jwt/jwt/v4 v4.0.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= +github.com/golang-jwt/jwt/v4 v4.4.3/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= +github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg= +github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= +github.com/golang-jwt/jwt/v5 v5.0.0/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= +github.com/golang-jwt/jwt/v5 v5.2.1 h1:OuVbFODueb089Lh128TAcimifWaLhJwVflnrgM17wHk= +github.com/golang-jwt/jwt/v5 v5.2.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= +github.com/golang-migrate/migrate/v4 v4.17.1 h1:4zQ6iqL6t6AiItphxJctQb3cFqWiSpMnX7wLTPnnYO4= +github.com/golang-migrate/migrate/v4 v4.17.1/go.mod h1:m8hinFyWBn0SA4QKHuKh175Pm9wjmxj3S2Mia7dbXzM= +github.com/golang-module/carbon/v2 v2.3.12 h1:VC1DwN1kBwJkh5MjXmTFryjs5g4CWyoM8HAHffZPX/k= +github.com/golang-module/carbon/v2 v2.3.12/go.mod h1:HNsedGzXGuNciZImYP2OMnpiwq/vhIstR/vn45ib5cI= +github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 h1:au07oEsX2xN0ktxqI+Sida1w446QrXBRJ0nee3SNZlA= +github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= +github.com/golang-sql/sqlexp v0.1.0 h1:ZCD6MBpcuOVfGVqsEmY5/4FtYiKz6tSyUv9LPEDei6A= +github.com/golang-sql/sqlexp v0.1.0/go.mod h1:J4ad9Vo8ZCWQ2GMrC4UCQy1JpCbwU9m3EOqtpKwwwHI= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= +github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= +github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= +github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= +github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/gomodule/redigo v1.8.2/go.mod h1:P9dn9mFrCBvWhGE1wpxx6fgq7BAeLBk+UUUzlpkBYO0= +github.com/gomodule/redigo v1.9.2/go.mod h1:KsU3hiK/Ay8U42qpaJk+kuNa3C+spxapWpM+ywhcgtw= +github.com/gomodule/redigo v2.0.0+incompatible h1:K/R+8tc58AaqLkqG2Ol3Qk+DR/TlNuhuh457pBFPtt0= +github.com/gomodule/redigo v2.0.0+incompatible/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4= +github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= +github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26 h1:Xim43kblpZXfIBQsbuBVKCudVG457BR2GZFIz3uw3hQ= +github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26/go.mod h1:dDKJzRmX4S37WGHujM7tX//fmj1uioxKzKxz3lo4HJo= +github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/s2a-go v0.1.7 h1:60BLSyTrOV4/haCDW4zb1guZItoSq8foHCXrAnjBo/o= +github.com/google/s2a-go v0.1.7/go.mod h1:50CgR4k1jNlWBu4UfS4AcfhVe1r6pdZPygJ3R8F0Qdw= +github.com/google/subcommands v1.2.0/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk= +github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/wire v0.6.0 h1:HBkoIh4BdSxoyo9PveV8giw7ZsaBOvzWKfcg/6MrVwI= +github.com/google/wire v0.6.0/go.mod h1:F4QhpQ9EDIdJ1Mbop/NZBRB+5yrR6qg3BnctaoUk6NA= +github.com/googleapis/enterprise-certificate-proxy v0.3.2 h1:Vie5ybvEvT75RniqhfFxPRy3Bf7vr3h0cechB90XaQs= +github.com/googleapis/enterprise-certificate-proxy v0.3.2/go.mod h1:VLSiSSBs/ksPL8kq3OBOQ6WRI2QnaFynd1DCjZ62+V0= +github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= +github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= +github.com/googleapis/gax-go/v2 v2.12.3 h1:5/zPPDvw8Q1SuXjrqrZslrqT7dL/uJT2CQii/cLCKqA= +github.com/googleapis/gax-go/v2 v2.12.3/go.mod h1:AKloxT6GtNbaLm8QTNSidHUVsHYcBHwWRvkNFJUQcS4= +github.com/gookit/color v1.4.2/go.mod h1:fqRyamkC1W8uxl+lxCQxOT09l/vYfZ+QeiX3rKQHCoQ= +github.com/gookit/color v1.5.0/go.mod h1:43aQb+Zerm/BWh2GnrgOQm7ffz7tvQXEKV6BFMl7wAo= +github.com/gookit/color v1.5.4 h1:FZmqs7XOyGgCAxmWyPslpiok1k05wmY3SJTytgvYFs0= +github.com/gookit/color v1.5.4/go.mod h1:pZJOeOS8DM43rXbp4AZo1n9zCU2qjpcRko0b6/QJi9w= +github.com/gookit/filter v1.2.1 h1:37XivkBm2E5qe1KaGdJ5ZfF5l9NYdGWfLEeQadJD8O4= +github.com/gookit/filter v1.2.1/go.mod h1:rxynQFr793x+XDwnRmJFEb53zDw0Zqx3OD7TXWoR9mQ= +github.com/gookit/goutil v0.6.15 h1:mMQ0ElojNZoyPD0eVROk5QXJPh2uKR4g06slgPDF5Jo= +github.com/gookit/goutil v0.6.15/go.mod h1:qdKdYEHQdEtyH+4fNdQNZfJHhI0jUZzHxQVAV3DaMDY= +github.com/gookit/validate v1.5.2 h1:i5I2OQ7WYHFRPRATGu9QarR9snnNHydvwSuHXaRWAV0= +github.com/gookit/validate v1.5.2/go.mod h1:yuPy2WwDlwGRa06fFJ5XIO8QEwhRnTC2LmxmBa5SE14= +github.com/goravel/fiber v1.2.1 h1:+hVmrxDzbT1bF/9bIgYytnROTgF1u+xgiVGM3N0S1E4= +github.com/goravel/fiber v1.2.1/go.mod h1:DB4QvgQ/WBqgXGs1cemhqAHFvj7jtI/Irk0RhHBWKoQ= +github.com/goravel/file-rotatelogs/v2 v2.4.2 h1:g68AzbePXcm0V2CpUMc9j4qVzcDn7+7aoWSjZ51C0m4= +github.com/goravel/file-rotatelogs/v2 v2.4.2/go.mod h1:23VuSW8cBS4ax5cmbV+5AaiLpq25b8UJ96IhbAkdo8I= +github.com/goravel/framework v1.14.1 h1:VcJvzn1ItFQh/rQZO1EMkxKmzDrww1S+OGz4hjZi3UY= +github.com/goravel/framework v1.14.1/go.mod h1:rScDXGQZdoVfyxemNPmijlz/2a+lWNOa4jTuak5GGVg= +github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4= +github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM= +github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 h1:UH//fgunKIs4JdUbpDl1VZCDaL56wXCB/5+wF6uHfaI= +github.com/grpc-ecosystem/go-grpc-middleware v1.4.0/go.mod h1:g5qyo/la0ALbONm6Vbp88Yd8NsDy6rZz+RcrMPxvld8= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= +github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= +github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= +github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= +github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a h1:bbPeKD0xmW/Y25WS6cokEszi5g+S0QxI/d45PkRi7Nk= +github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= +github.com/jackc/pgx/v5 v5.5.4 h1:Xp2aQS8uXButQdnCMWNmvx6UysWQQC+u1EoizjguY+8= +github.com/jackc/pgx/v5 v5.5.4/go.mod h1:ez9gk+OAat140fv9ErkZDYFWmXLfV+++K0uAOiwgm1A= +github.com/jackc/puddle/v2 v2.2.1 h1:RhxXJtFG022u4ibrCSMSiu5aOq1i77R3OHKNJj77OAk= +github.com/jackc/puddle/v2 v2.2.1/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4= +github.com/jcmturner/aescts/v2 v2.0.0/go.mod h1:AiaICIRyfYg35RUkr8yESTqvSy7csK90qZ5xfvvsoNs= +github.com/jcmturner/dnsutils/v2 v2.0.0/go.mod h1:b0TnjGOvI/n42bZa+hmXL+kFJZsFT7G4t3HTlQ184QM= +github.com/jcmturner/gofork v1.7.6/go.mod h1:1622LH6i/EZqLloHfE7IeZ0uEJwMSUyQ/nDd82IeqRo= +github.com/jcmturner/goidentity/v6 v6.0.1/go.mod h1:X1YW3bgtvwAXju7V3LCIMpY0Gbxyjn/mY9zx4tFonSg= +github.com/jcmturner/gokrb5/v8 v8.4.4/go.mod h1:1btQEpgT6k+unzCwX1KdWMEwPPkkgBtP+F6aCACiMrs= +github.com/jcmturner/rpc/v2 v2.0.3/go.mod h1:VUJYCIDm3PVOEHw8sgt091/20OJjskO/YJki3ELg/Hc= +github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= +github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= +github.com/jinzhu/now v1.1.4/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= +github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ= +github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= +github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= +github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= +github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8= +github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= +github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg= +github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= +github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= +github.com/karrick/godirwalk v1.8.0/go.mod h1:H5KPZjojv4lE+QYImBI8xVtrBRgYrIVsaRPx4tDPEn4= +github.com/karrick/godirwalk v1.10.3/go.mod h1:RoGL9dQei4vP9ilrpETWE8CLOZ1kiN0LhBygSwrAsHA= +github.com/kelseyhightower/envconfig v1.4.0 h1:Im6hONhd3pLkfDFsbRgu68RDNkGF1r3dvMUtDTo2cv8= +github.com/kelseyhightower/envconfig v1.4.0/go.mod h1:cccZRl6mQpaq41TPp5QxidR+Sa3axMbJDNb//FQX6Gg= +github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/klauspost/compress v1.9.5/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= +github.com/klauspost/compress v1.13.4/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg= +github.com/klauspost/compress v1.13.5/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= +github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= +github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA= +github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= +github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= +github.com/klauspost/cpuid/v2 v2.0.10/go.mod h1:g2LTdtYhdyuGPqyWyv7qRAmj1WBqxuObKfj5c0PQa7c= +github.com/klauspost/cpuid/v2 v2.0.12/go.mod h1:g2LTdtYhdyuGPqyWyv7qRAmj1WBqxuObKfj5c0PQa7c= +github.com/klauspost/cpuid/v2 v2.2.7 h1:ZWSB3igEs+d0qvnxR/ZBzXVmxkgt8DdzP6m9pfuVLDM= +github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= +github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= +github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= +github.com/lestrrat-go/envload v0.0.0-20180220234015-a3eb8ddeffcc h1:RKf14vYWi2ttpEmkA4aQ3j4u9dStX2t4M8UM6qqNsG8= +github.com/lestrrat-go/envload v0.0.0-20180220234015-a3eb8ddeffcc/go.mod h1:kopuH9ugFRkIXf3YoqHKyrJ9YfUFsckUU9S7B+XP+is= +github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= +github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= +github.com/lithammer/fuzzysearch v1.1.8 h1:/HIuJnjHuXS8bKaiTMeeDlW2/AyIWk2brx1V8LFgLN4= +github.com/lithammer/fuzzysearch v1.1.8/go.mod h1:IdqeyBClc3FFqSzYq/MXESsS4S0FsZ5ajtkr5xPLts4= +github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY= +github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= +github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= +github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= +github.com/markbates/oncer v0.0.0-20181203154359-bf2de49a0be2/go.mod h1:Ld9puTsIW75CHf65OeIOkyKbteujpZVXDpWK6YGZbxE= +github.com/markbates/safe v1.0.1/go.mod h1:nAqgmRi7cY2nqMc92/bSEeQA+R4OheNU2T1kNSCBdG0= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mattn/go-localereader v0.0.1 h1:ygSAOl7ZXTx4RdPYinUpg6W99U8jWvWi9Ye2JC/oIi4= +github.com/mattn/go-localereader v0.0.1/go.mod h1:8fBrzywKY7BI3czFoHkuzRoWE9C+EiG4R1k4Cjx5p88= +github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U= +github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +github.com/microsoft/go-mssqldb v1.6.0 h1:mM3gYdVwEPFrlg/Dvr2DNVEgYFG7L42l+dGc67NNNpc= +github.com/microsoft/go-mssqldb v1.6.0/go.mod h1:00mDtPbeQCRGC1HwOOR5K/gr30P1NcEG0vx6Kbv2aJU= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0= +github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y= +github.com/modocache/gover v0.0.0-20171022184752-b58185e213c5/go.mod h1:caMODM3PzxT8aQXRPkAt8xlV/e7d7w8GM5g0fa5F0D8= +github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc= +github.com/montanaflynn/stats v0.7.0/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow= +github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A= +github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= +github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 h1:ZK8zHtRHOkbHy6Mmr5D264iyp3TiX5OmNcI5cIARiQI= +github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6/go.mod h1:CJlz5H+gyd6CUWT45Oy4q24RdLyn7Md9Vj2/ldJBSIo= +github.com/muesli/cancelreader v0.2.2 h1:3I4Kt4BQjOR54NavqnDogx/MIoWBFa0StPA8ELUXHmA= +github.com/muesli/cancelreader v0.2.2/go.mod h1:3XuTXfFS2VjM+HTLZY9Ak0l6eUKfijIfMUZ4EgX0QYo= +github.com/muesli/termenv v0.15.2 h1:GohcuySI0QmI3wN8Ok9PtKGkgkFIk7y6Vpb5PvrY+Wo= +github.com/muesli/termenv v0.15.2/go.mod h1:Epx+iuz8sNs7mNKhxzH4fWXGNpZwUaJKRS1noLXviQ8= +github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= +github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= +github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= +github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= +github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= +github.com/onsi/gomega v1.16.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= +github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= +github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= +github.com/opencontainers/image-spec v1.0.2 h1:9yCKha/T5XdGtO0q9Q9a6T5NUCsTn/DrBg0D7ufOcFM= +github.com/opencontainers/image-spec v1.0.2/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= +github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= +github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs= +github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc= +github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc= +github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ= +github.com/pelletier/go-toml v1.7.0/go.mod h1:vwGMzjaWMwyfHwgIBhI2YUM4fB6nL6lVAvS1LBMMhTE= +github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM= +github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs= +github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 h1:KoWmjvw+nsYOo29YJK9vDA65RGE3NrOnUtO7a+RF9HU= +github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8/go.mod h1:HKlIX3XHQyzLZPlr7++PzdhaXEj94dEiJgZDTsxEqUI= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/pterm/pterm v0.12.27/go.mod h1:PhQ89w4i95rhgE+xedAoqous6K9X+r6aSOI2eFF7DZI= +github.com/pterm/pterm v0.12.29/go.mod h1:WI3qxgvoQFFGKGjGnJR849gU0TsEOvKn5Q8LlY1U7lg= +github.com/pterm/pterm v0.12.30/go.mod h1:MOqLIyMOgmTDz9yorcYbcw+HsgoZo3BQfg2wtl3HEFE= +github.com/pterm/pterm v0.12.31/go.mod h1:32ZAWZVXD7ZfG0s8qqHXePte42kdz8ECtRyEejaWgXU= +github.com/pterm/pterm v0.12.33/go.mod h1:x+h2uL+n7CP/rel9+bImHD5lF3nM9vJj80k9ybiiTTE= +github.com/pterm/pterm v0.12.36/go.mod h1:NjiL09hFhT/vWjQHSj1athJpx6H8cjpHXNAK5bUw8T8= +github.com/pterm/pterm v0.12.40/go.mod h1:ffwPLwlbXxP+rxT0GsgDTzS3y3rmpAO1NMjUkGTYf8s= +github.com/pterm/pterm v0.12.79 h1:lH3yrYMhdpeqX9y5Ep1u7DejyHy7NSQg9qrBjF9dFT4= +github.com/pterm/pterm v0.12.79/go.mod h1:1v/gzOF1N0FsjbgTHZ1wVycRkKiatFvJSJC4IGaQAAo= +github.com/rabbitmq/amqp091-go v1.9.0 h1:qrQtyzB4H8BQgEuJwhmVQqVHB9O4+MNDJCCAcpc3Aoo= +github.com/rabbitmq/amqp091-go v1.9.0/go.mod h1:+jPrT9iY2eLjRaMSRHUhc3z14E/l85kv/f+6luSD3pc= +github.com/redis/go-redis/v9 v9.0.2/go.mod h1:/xDTe9EF1LM61hek62Poq2nzQSGj0xSrEtEHbBQevps= +github.com/redis/go-redis/v9 v9.0.5/go.mod h1:WqMKv5vnQbRuZstUwxQI195wHy+t4PuXDOjzMvcuQHk= +github.com/redis/go-redis/v9 v9.5.3 h1:fOAp1/uJG+ZtcITgZOfYFmTKPE7n4Vclj1wZFgRciUU= +github.com/redis/go-redis/v9 v9.5.3/go.mod h1:hdY0cQFCN4fnSYT6TkisLufl/4W5UIXyv0b/CLO2V2M= +github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE= +github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= +github.com/rifflock/lfshook v0.0.0-20180920164130-b9218ef580f5 h1:mZHayPoR0lNmnHyvtYjDeq0zlVHn9K/ZXoy17ylucdo= +github.com/rifflock/lfshook v0.0.0-20180920164130-b9218ef580f5/go.mod h1:GEXHk5HgEKCvEIIrSpFI3ozzG5xOKA2DVlEX/gGnewM= +github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= +github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= +github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= +github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs= +github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro= +github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rogpeppe/go-internal v1.2.2/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= +github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA= +github.com/rotisserie/eris v0.5.4 h1:Il6IvLdAapsMhvuOahHWiBnl1G++Q0/L5UIkI5mARSk= +github.com/rotisserie/eris v0.5.4/go.mod h1:Z/kgYTJiJtocxCbFfvRmO+QejApzG6zpyky9G1A4g9s= +github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= +github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/sagikazarmark/locafero v0.4.0 h1:HApY1R9zGo4DBgr7dqsTH/JJxLTTsOt7u6keLGt6kNQ= +github.com/sagikazarmark/locafero v0.4.0/go.mod h1:Pe1W6UlPYUk/+wc/6KFhbORCfqzgYEpgQ3O5fPuL3H4= +github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE= +github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ= +github.com/savioxavier/termlink v1.3.0 h1:3Gl4FzQjUyiHzmoEDfmWEhgIwDiJY4poOQHP+k8ReA4= +github.com/savioxavier/termlink v1.3.0/go.mod h1:5T5ePUlWbxCHIwyF8/Ez1qufOoGM89RCg9NvG+3G3gc= +github.com/sergi/go-diff v1.2.0 h1:XU+rvMAioB0UC3q1MFrIQy4Vo5/4VsRDQQXHsEya6xQ= +github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= +github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/sirupsen/logrus v1.4.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= +github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo= +github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0= +github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8= +github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY= +github.com/spf13/cast v1.6.0 h1:GEiTHELF+vaR5dhz3VqZfFSzZjYbgeKDpBxQVS4GYJ0= +github.com/spf13/cast v1.6.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= +github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= +github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/viper v1.19.0 h1:RWq5SEjt8o25SROyN3z2OrDB9l7RPd3lwTWU8EcEdcI= +github.com/spf13/viper v1.19.0/go.mod h1:GQUN9bilAbhU/jgc1bKs99f/suXKeUMct8Adx5+Ntkg= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= +github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/stvp/tempredis v0.0.0-20181119212430-b82af8480203 h1:QVqDTf3h2WHt08YuiTGPZLls0Wq99X9bWd0Q5ZSBesM= +github.com/stvp/tempredis v0.0.0-20181119212430-b82af8480203/go.mod h1:oqN97ltKNihBbwlX8dLpwxCl3+HnXKV/R0e+sRLd9C8= +github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= +github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= +github.com/tidwall/pretty v1.0.0 h1:HsD+QiTn7sK6flMKIvNmpqz1qrpP3Ps6jOKIKMooyg4= +github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= +github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= +github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= +github.com/urfave/cli v1.22.5/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= +github.com/urfave/cli/v2 v2.27.2 h1:6e0H+AkS+zDckwPCUrZkKX38mRaau4nL2uipkJpbkcI= +github.com/urfave/cli/v2 v2.27.2/go.mod h1:g0+79LmHHATl7DAcHO99smiR/T7uGLw84w8Y42x+4eM= +github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= +github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= +github.com/valyala/fasthttp v1.30.0/go.mod h1:2rsYD01CKFrjjsvFxx75KlEUNpWNBY9JWD3K/7o2Cus= +github.com/valyala/fasthttp v1.55.0 h1:Zkefzgt6a7+bVKHnu/YaYSOPfNYNisSVBo/unVCf8k8= +github.com/valyala/fasthttp v1.55.0/go.mod h1:NkY9JtkrpPKmgwV3HTaS2HWaJss9RSIsRVfcxxoHiOM= +github.com/valyala/quicktemplate v1.7.0 h1:LUPTJmlVcb46OOUY3IeD9DojFpAVbsG+5WFTcjMJzCM= +github.com/valyala/quicktemplate v1.7.0/go.mod h1:sqKJnoaOF88V07vkO+9FL8fb9uZg/VPSJnLYn+LmLk8= +github.com/valyala/tcplisten v1.0.0 h1:rBHj/Xf+E1tRGZyWIWwJDiRY0zc1Js+CV5DqwacVSA8= +github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc= +github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c= +github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI= +github.com/xdg-go/scram v1.0.2/go.mod h1:1WAq6h33pAW+iRreB34OORO2Nf7qel3VV3fjBj+hCSs= +github.com/xdg-go/scram v1.1.1 h1:VOMT+81stJgXW3CpHyqHN3AXDYIMsx56mEFrB37Mb/E= +github.com/xdg-go/scram v1.1.1/go.mod h1:RaEWvsqvNKKvBPvcKeFjrG2cJqOkHTiyTpzz23ni57g= +github.com/xdg-go/stringprep v1.0.2/go.mod h1:8F9zXuvzgwmyT5DUm4GUfZGDdT3W+LCvS6+da4O5kxM= +github.com/xdg-go/stringprep v1.0.3 h1:kdwGpVNwPFtjs98xCGkHjQtGKh86rDcRZN17QEMCOIs= +github.com/xdg-go/stringprep v1.0.3/go.mod h1:W3f5j4i+9rC0kuIEJL0ky1VpHXQU3ocBgklLGvcBnW8= +github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c/go.mod h1:lB8K/P019DLNhemzwFU4jHLhdvlE6uDZjXFejJXr49I= +github.com/xdg/stringprep v0.0.0-20180714160509-73f8eece6fdc/go.mod h1:Jhud4/sHMO4oL310DaZAKk9ZaJ08SJfe+sJh0HrGL1Y= +github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778/go.mod h1:2MuV+tbUrU1zIOPMxZ5EncGwgmMJsa+9ucAQZXxsObs= +github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e h1:JVG44RsyaB9T2KIHavMF/ppJZNG9ZpyihvCd0w101no= +github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e/go.mod h1:RbqR21r5mrJuqunuUZ/Dhy/avygyECGrLceyNeo4LiM= +github.com/xrash/smetrics v0.0.0-20240312152122-5f08fbb34913 h1:+qGGcbkzsfDQNPPe9UDgpxAWQrhbbBXOYJFQDq/dtJw= +github.com/xrash/smetrics v0.0.0-20240312152122-5f08fbb34913/go.mod h1:4aEEwZQutDLsQv2Deui4iYQ6DWTxR14g6m8Wv88+Xqk= +github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d h1:splanxYIlg+5LfHAM6xpdFEAYOk8iySO56hMFq6uLyA= +github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA= +github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +go.einride.tech/aip v0.66.0 h1:XfV+NQX6L7EOYK11yoHHFtndeaWh3KbD9/cN/6iWEt8= +go.einride.tech/aip v0.66.0/go.mod h1:qAhMsfT7plxBX+Oy7Huol6YUvZ0ZzdUz26yZsQwfl1M= +go.mongodb.org/mongo-driver v1.4.6/go.mod h1:WcMNYLx/IlOxLe6JRJiv2uXuCz6zBLndR4SoGjYphSc= +go.mongodb.org/mongo-driver v1.7.5 h1:ny3p0reEpgsR2cfA5cjgwFZg3Cv/ofFh/8jbhGtz9VI= +go.mongodb.org/mongo-driver v1.7.5/go.mod h1:VXEWRZ6URJIkUq2SCAyapmhH0ZLRBP+FT4xhp5Zvxng= +go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= +go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= +go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= +go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= +go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0 h1:4Pp6oUg3+e/6M4C0A/3kJ2VYa++dsWVTtGgLVj5xtHg= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0/go.mod h1:Mjt1i1INqiaoZOMGR1RIUJN+i3ChKoFRqzrRQhlkbs0= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 h1:jq9TW8u3so/bN+JPT166wjOI6/vQPF6Xe7nMNIltagk= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0/go.mod h1:p8pYQP+m5XfbZm9fxtSKAbM6oIllS7s2AfxrChvc7iw= +go.opentelemetry.io/otel v1.24.0 h1:0LAOdjNmQeSTzGBzduGe/rU4tZhMwL5rWgtp9Ku5Jfo= +go.opentelemetry.io/otel v1.24.0/go.mod h1:W7b9Ozg4nkF5tWI5zsXkaKKDjdVjpD4oAt9Qi/MArHo= +go.opentelemetry.io/otel/metric v1.24.0 h1:6EhoGWWK28x1fbpA4tYTOWBkPefTDQnb8WSGXlc88kI= +go.opentelemetry.io/otel/metric v1.24.0/go.mod h1:VYhLe1rFfxuTXLgj4CBiyz+9WYBA8pNGJgDcSFRKBco= +go.opentelemetry.io/otel/sdk v1.22.0 h1:6coWHw9xw7EfClIC/+O31R8IY3/+EiRFHevmHafB2Gw= +go.opentelemetry.io/otel/sdk v1.22.0/go.mod h1:iu7luyVGYovrRpe2fmj3CVKouQNdTOkxtLzPvPz1DOc= +go.opentelemetry.io/otel/trace v1.24.0 h1:CsKnnL4dUAr/0llH9FKuc698G04IrpWV0MQA/Y1YELI= +go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU= +go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE= +go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= +go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= +go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A= +go.uber.org/goleak v1.2.1/go.mod h1:qlT2yGI9QafXHhZZLxlSuNsMw3FFLxBr+tBRlmO1xH4= +go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= +go.uber.org/multierr v1.9.0 h1:7fIwc/ZtS0q++VgcfqFDxSBZVv/Xo49/SYnDFupUwlI= +go.uber.org/multierr v1.9.0/go.mod h1:X2jQV1h+kxSjClGpnseKVIxpmcjrj7MNnI0bnlfKTVQ= +go.uber.org/zap v1.18.1/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI= +golang.org/x/arch v0.0.0-20210923205945-b76863e36670 h1:18EFjUmQOcUvxNYSkA6jO9VAiXCnxFY6NyDX0bHDmkU= +golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190422162423-af44ce270edf/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= +golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190530122614-20be4c3c3ed5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= +golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= +golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0= +golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw= +golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= +golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg= +golang.org/x/crypto v0.24.0 h1:mnl8DM0o513X8fdIkmyFE/5hTYxbwYOjDS/+rK6qpRI= +golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= +golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= +golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= +golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= +golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= +golang.org/x/exp v0.0.0-20230905200255-921286631fa9 h1:GoHiUyI/Tp2nVkLI2mCxVkOjsbSXD66ic0XW0js0R9g= +golang.org/x/exp v0.0.0-20230905200255-921286631fa9/go.mod h1:S2oDrQGGwySpoQPVqRShND87VCbxmc6bL1Yd2oYrm6k= +golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= +golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= +golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= +golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= +golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= +golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= +golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA= +golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= +golang.org/x/net v0.0.0-20210510120150-4163338589ed/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= +golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI= +golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= +golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY= +golang.org/x/net v0.26.0 h1:soB7SVo0PWrY4vPW/+ay0jKDNScG2X9wFeYlXIvJsOQ= +golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210113205817-d3ed898aa8a3/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.18.0 h1:09qnuIAgzdx1XplqJvW6CQqMCtGZykZWcXzPMPUusvI= +golang.org/x/oauth2 v0.18.0/go.mod h1:Wf7knwG0MPoWIMMBgFlEaSUDaKskp0dCfrlJRJXbBi8= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190412183630-56d357773e84/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= +golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= +golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190419153524-e8e3143a4f4a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190531175056-4c3a928424d2/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191010194322-b09406accb47/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210616045830-e2b7044e8c71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211013075003-97ac67df715c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws= +golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= +golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= +golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU= +golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU= +golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY= +golang.org/x/term v0.21.0 h1:WVXCp+/EBEHOj53Rvu+7KiT/iElMrO8ACK16SMZ3jaA= +golang.org/x/term v0.21.0/go.mod h1:ooXLefLobQVslOqselCNF4SxFAaoS6KujMbsGzSDmX0= +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4= +golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= +golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20201208040808-7e3f01d25324/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= +golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190329151228-23e29df326fe/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190416151739-9c9e1878f421/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190420181800-aa740d480789/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190531172133-b3315ee88b7d/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= +golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= +golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= +golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= +golang.org/x/tools v0.17.0/go.mod h1:xsh6VxdV005rRVaS6SSAf9oiAqljS7UZUacMZ8Bnsps= +golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg= +golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= +google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= +google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= +google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= +google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= +google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE= +google.golang.org/api v0.39.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= +google.golang.org/api v0.171.0 h1:w174hnBPqut76FzW5Qaupt7zY8Kql6fiVjgys4f58sU= +google.golang.org/api v0.171.0/go.mod h1:Hnq5AHm4OTMt2BUVjael2CWZFD6vksJdWCWiUAmjC9o= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= +google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM= +google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= +google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= +google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200423170343-7949de9c1215/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= +google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210207032614-bba0dbe2a9ea/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de h1:F6qOa9AZTYJXOUEr4jDysRDLrm4PHePlge4v4TGAlxY= +google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de/go.mod h1:VUhTRKeHn9wwcdrk73nvdC9gF178Tzhmt/qyaFcPLSo= +google.golang.org/genproto/googleapis/api v0.0.0-20240318140521-94a12d6c2237 h1:RFiFrvy37/mpSpdySBDrUdipW/dHwsRwh3J3+A9VgT4= +google.golang.org/genproto/googleapis/api v0.0.0-20240318140521-94a12d6c2237/go.mod h1:Z5Iiy3jtmioajWHDGFk7CeugTyHtPvMHA4UTmUkyalE= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237 h1:NnYq6UN9ReLM9/Y01KWNOWyI5xQ9kbIms5GGJVwS/Yc= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237/go.mod h1:WtryC6hu0hhx87FDGxWCDptyssuo68sk10vYjF+T9fY= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= +google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= +google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= +google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= +google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= +google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= +google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.64.0 h1:KH3VH9y/MgNQg1dE7b3XfVK0GsPSIzJwdF617gUSbvY= +google.golang.org/grpc v1.64.0/go.mod h1:oxjF8E3FBnjp+/gVFYdWacaLDx9na1aqy9oovLpxQYg= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= +google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg= +google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= +gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gorm.io/driver/mysql v1.4.3/go.mod h1:sSIebwZAVPiT+27jK9HIwvsqOGKx3YMPmrA3mBJR10c= +gorm.io/driver/mysql v1.5.6 h1:Ld4mkIickM+EliaQZQx3uOJDJHtrd70MxAUqWqlx3Y8= +gorm.io/driver/mysql v1.5.6/go.mod h1:sEtPWMiqiN1N1cMXoXmBbd8C6/l+TESwriotuRRpkDM= +gorm.io/driver/postgres v1.5.7 h1:8ptbNJTDbEmhdr62uReG5BGkdQyeasu/FZHxI0IMGnM= +gorm.io/driver/postgres v1.5.7/go.mod h1:3e019WlBaYI5o5LIdNV+LyxCMNtLOQETBXL2h4chKpA= +gorm.io/driver/sqlserver v1.5.3 h1:rjupPS4PVw+rjJkfvr8jn2lJ8BMhT4UW5FwuJY0P3Z0= +gorm.io/driver/sqlserver v1.5.3/go.mod h1:B+CZ0/7oFJ6tAlefsKoyxdgDCXJKSgwS2bMOQZT0I00= +gorm.io/gorm v1.23.8/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk= +gorm.io/gorm v1.25.2/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k= +gorm.io/gorm v1.25.7-0.20240204074919-46816ad31dde/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8= +gorm.io/gorm v1.25.7/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8= +gorm.io/gorm v1.25.10 h1:dQpO+33KalOA+aFYGlK+EfxcI5MbO7EP2yYygwh9h+s= +gorm.io/gorm v1.25.10/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8= +gorm.io/plugin/dbresolver v1.5.1 h1:s9Dj9f7r+1rE3nx/Ywzc85nXptUEaeOO0pt27xdopM8= +gorm.io/plugin/dbresolver v1.5.1/go.mod h1:l4Cn87EHLEYuqUncpEeTC2tTJQkjngPSD+lo8hIvcT0= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +modernc.org/libc v1.37.6 h1:orZH3c5wmhIQFTXF+Nt+eeauyd+ZIt2BX6ARe+kD+aw= +modernc.org/libc v1.37.6/go.mod h1:YAXkAZ8ktnkCKaN9sw/UDeUVkGYJ/YquGO4FTi5nmHE= +modernc.org/mathutil v1.6.0 h1:fRe9+AmYlaej+64JsEEhoWuAYBkOtQiMEU7n/XgfYi4= +modernc.org/mathutil v1.6.0/go.mod h1:Ui5Q9q1TR2gFm0AQRqQUaBWFLAhQpCwNcuhBOSedWPo= +modernc.org/memory v1.7.2 h1:Klh90S215mmH8c9gO98QxQFsY+W451E8AnzjoE2ee1E= +modernc.org/memory v1.7.2/go.mod h1:NO4NVCQy0N7ln+T9ngWqOQfi7ley4vpwvARR+Hjw95E= +modernc.org/sqlite v1.28.0 h1:Zx+LyDDmXczNnEQdvPuEfcFVA2ZPyaD7UCZDjef3BHQ= +modernc.org/sqlite v1.28.0/go.mod h1:Qxpazz0zH8Z1xCFyi5GSL3FzbtZ3fvbjmywNogldEW0= +nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50= +rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= +rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= +rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= +rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= diff --git a/frameworks/Go/goravel/src/fiber/main.go b/frameworks/Go/goravel/src/fiber/main.go new file mode 100644 index 00000000000..ddd89a4e1a1 --- /dev/null +++ b/frameworks/Go/goravel/src/fiber/main.go @@ -0,0 +1,27 @@ +package main + +import ( + "github.com/goravel/framework/facades" + "github.com/goravel/framework/foundation" + + "goravel/config" +) + +func main() { + app := foundation.NewApplication() + + // Bootstrap the application + app.Boot() + + // Bootstrap the config. + config.Boot() + + // Start HTTP server by facades.Route(). + go func() { + if err := facades.Route().Run(); err != nil { + facades.Log().Errorf("Route run error: %v", err) + } + }() + + select {} +} diff --git a/frameworks/Go/goravel/src/fiber/routes/web.go b/frameworks/Go/goravel/src/fiber/routes/web.go new file mode 100644 index 00000000000..86bfbccc2d4 --- /dev/null +++ b/frameworks/Go/goravel/src/fiber/routes/web.go @@ -0,0 +1,19 @@ +package routes + +import ( + "github.com/goravel/framework/facades" + + "goravel/app/http/controllers" +) + +func Web() { + testController := controllers.NewTestController() + facades.Route().Get("/plaintext", testController.Plaintext) + facades.Route().Get("/json", testController.JSON) + facades.Route().Get("/db", testController.DB) + facades.Route().Get("/queries", testController.Queries) + facades.Route().Get("/update", testController.Update) + facades.Route().Get("/fortunes", testController.Fortunes) + facades.Route().Get("/cached-worlds", testController.CacheQueries) + +} diff --git a/frameworks/Go/goravel/src/fiber/templates/fortune.go b/frameworks/Go/goravel/src/fiber/templates/fortune.go new file mode 100644 index 00000000000..1d41ca2c80d --- /dev/null +++ b/frameworks/Go/goravel/src/fiber/templates/fortune.go @@ -0,0 +1,53 @@ +package templates + +import ( + "sync" +) + +type Fortune struct { + ID int `json:"id,omitempty"` + Message string `json:"message,omitempty"` +} + +type Fortunes struct { + F []Fortune +} + +//go:generate go run github.com/valyala/quicktemplate/qtc + +var fortunePool = &sync.Pool{ + New: func() interface{} { + return new(Fortune) + }, +} + +var fortunesPool = &sync.Pool{ + New: func() interface{} { + return &Fortunes{ + F: make([]Fortune, 0), + } + }, +} + +// AcquireFortune returns new message from pool. +func AcquireFortune() *Fortune { + return fortunePool.Get().(*Fortune) +} + +// ReleaseFortune resets the message and return it to the pool. +func ReleaseFortune(f *Fortune) { + f.ID = 0 + f.Message = "" + fortunePool.Put(f) +} + +// AcquireFortunes returns new fortunes from pool. +func AcquireFortunes() *Fortunes { + return fortunesPool.Get().(*Fortunes) +} + +// ReleaseFortunes resets the fortunes and return it to the pool. +func ReleaseFortunes(f *Fortunes) { + f.F = f.F[:0] + fortunesPool.Put(f) +} diff --git a/frameworks/Go/goravel/src/fiber/templates/fortune.qtpl b/frameworks/Go/goravel/src/fiber/templates/fortune.qtpl new file mode 100644 index 00000000000..d387990d4ae --- /dev/null +++ b/frameworks/Go/goravel/src/fiber/templates/fortune.qtpl @@ -0,0 +1,15 @@ +{% func FortunePage(rows []Fortune) %} + + +Fortunes + + + + +{% for _, r := range rows %} + +{% endfor %} +
idmessage
{%d int(r.ID) %}{%s r.Message %}
+ + +{% endfunc %} diff --git a/frameworks/Go/goravel/src/fiber/templates/fortune.qtpl.go b/frameworks/Go/goravel/src/fiber/templates/fortune.qtpl.go new file mode 100644 index 00000000000..8af0bbf4f10 --- /dev/null +++ b/frameworks/Go/goravel/src/fiber/templates/fortune.qtpl.go @@ -0,0 +1,81 @@ +// Code generated by qtc from "fortune.qtpl". DO NOT EDIT. +// See https://github.com/valyala/quicktemplate for details. + +//line fortune.qtpl:1 +package templates + +//line fortune.qtpl:1 +import ( + qtio422016 "io" + + qt422016 "github.com/valyala/quicktemplate" +) + +//line fortune.qtpl:1 +var ( + _ = qtio422016.Copy + _ = qt422016.AcquireByteBuffer +) + +//line fortune.qtpl:1 +func StreamFortunePage(qw422016 *qt422016.Writer, rows []Fortune) { +//line fortune.qtpl:1 + qw422016.N().S(` + + +Fortunes + + + + +`) +//line fortune.qtpl:9 + for _, r := range rows { +//line fortune.qtpl:9 + qw422016.N().S(` + +`) +//line fortune.qtpl:11 + } +//line fortune.qtpl:11 + qw422016.N().S(` +
idmessage
`) +//line fortune.qtpl:10 + qw422016.N().D(int(r.ID)) +//line fortune.qtpl:10 + qw422016.N().S(``) +//line fortune.qtpl:10 + qw422016.E().S(r.Message) +//line fortune.qtpl:10 + qw422016.N().S(`
+ + +`) +//line fortune.qtpl:15 +} + +//line fortune.qtpl:15 +func WriteFortunePage(qq422016 qtio422016.Writer, rows []Fortune) { +//line fortune.qtpl:15 + qw422016 := qt422016.AcquireWriter(qq422016) +//line fortune.qtpl:15 + StreamFortunePage(qw422016, rows) +//line fortune.qtpl:15 + qt422016.ReleaseWriter(qw422016) +//line fortune.qtpl:15 +} + +//line fortune.qtpl:15 +func FortunePage(rows []Fortune) string { +//line fortune.qtpl:15 + qb422016 := qt422016.AcquireByteBuffer() +//line fortune.qtpl:15 + WriteFortunePage(qb422016, rows) +//line fortune.qtpl:15 + qs422016 := string(qb422016.B) +//line fortune.qtpl:15 + qt422016.ReleaseByteBuffer(qb422016) +//line fortune.qtpl:15 + return qs422016 +//line fortune.qtpl:15 +} diff --git a/frameworks/Go/goravel/src/gin/.env b/frameworks/Go/goravel/src/gin/.env new file mode 100644 index 00000000000..9ceb9e63dc9 --- /dev/null +++ b/frameworks/Go/goravel/src/gin/.env @@ -0,0 +1 @@ +APP_KEY=abcdefghijklmnopqrstuvwxyz123456 \ No newline at end of file diff --git a/frameworks/Go/goravel/src/gin/app/http/controllers/test_controller.go b/frameworks/Go/goravel/src/gin/app/http/controllers/test_controller.go new file mode 100644 index 00000000000..7b68b61daeb --- /dev/null +++ b/frameworks/Go/goravel/src/gin/app/http/controllers/test_controller.go @@ -0,0 +1,129 @@ +package controllers + +import ( + "math/rand/v2" + "sort" + + "github.com/goravel/framework/contracts/http" + "github.com/goravel/framework/facades" + + "goravel/app/models" +) + +type TestController struct{} + +func NewTestController() *TestController { + initCache() + return &TestController{} +} + +func (r *TestController) Plaintext(ctx http.Context) http.Response { + Plaintext(ctx, helloworld) + return nil +} + +func (r *TestController) JSON(ctx http.Context) http.Response { + message := acquireMessage() + message.Message = helloworld + + JSON(ctx, &message) + releaseMessage(message) + return nil +} + +func (r *TestController) DB(ctx http.Context) http.Response { + world := acquireWorld() + + world.ID = r.getRand() + _ = facades.Orm().Query().Find(&world) + + JSON(ctx, &world) + releaseWorld(world) + return nil +} + +func (r *TestController) Queries(ctx http.Context) http.Response { + n := r.getN(ctx) + worlds := acquireWorlds()[:n] + + for i := 0; i < n; i++ { + worlds[i].ID = r.getRand() + _ = facades.Orm().Query().Find(&worlds[i]) + } + + JSON(ctx, &worlds) + releaseWorlds(worlds) + return nil +} + +func (r *TestController) Update(ctx http.Context) http.Response { + n := r.getN(ctx) + worlds := acquireWorlds()[:n] + + for i := 0; i < n; i++ { + worlds[i].ID = r.getRand() + _ = facades.Orm().Query().Find(&worlds[i]) + } + + // sorting is required for insert deadlock prevention. + sort.Slice(worlds, func(i, j int) bool { + return worlds[i].ID < worlds[j].ID + }) + + tx, _ := facades.Orm().Query().Begin() + for i := 0; i < n; i++ { + worlds[i].RandomNumber = r.getRand() + _ = tx.Save(&worlds[i]) + } + _ = tx.Commit() + + JSON(ctx, &worlds) + releaseWorlds(worlds) + return nil +} + +func (r *TestController) Fortunes(ctx http.Context) http.Response { + fortunes := make([]models.Fortune, 0) + _ = facades.Orm().Query().Get(&fortunes) + fortunes = append(fortunes, models.Fortune{Message: "Additional fortune added at request time."}) + + sort.Slice(fortunes, func(i, j int) bool { + return fortunes[i].Message < fortunes[j].Message + }) + + return ctx.Response(). + Header("Server", "Goravel"). + View(). + Make("fortunes.tmpl", map[string]any{ + "fortunes": fortunes, + }) +} + +func (r *TestController) CacheQueries(ctx http.Context) http.Response { + n := r.getN(ctx) + worlds := acquireWorlds()[:n] + cached := facades.Cache().Get("worlds").(Worlds) + + for i := 0; i < n; i++ { + worlds[i] = cached[r.getRand()-1] + } + + JSON(ctx, &worlds) + releaseWorlds(worlds) + return nil +} + +func (r *TestController) getN(ctx http.Context) int { + n := ctx.Request().QueryInt(queryparam) + if n < 1 { + n = 1 + } else if n > 500 { + n = 500 + } + + return n +} + +func (r *TestController) getRand() int32 { + return rand.Int32N(worldcount) + 1 +} diff --git a/frameworks/Go/goravel/src/gin/app/http/controllers/utils.go b/frameworks/Go/goravel/src/gin/app/http/controllers/utils.go new file mode 100644 index 00000000000..9cac0d34b48 --- /dev/null +++ b/frameworks/Go/goravel/src/gin/app/http/controllers/utils.go @@ -0,0 +1,101 @@ +package controllers + +import ( + "fmt" + "sync" + "unsafe" + + "github.com/bytedance/sonic" + "github.com/goravel/framework/contracts/http" + "github.com/goravel/framework/facades" + + "goravel/app/models" +) + +const ( + queryparam = "q" + helloworld = "Hello, World!" + worldcount = 10000 + contentTypePlain = "text/plain; charset=utf-8" + contentTypeJson = "application/json" +) + +type Message struct { + Message string `json:"message"` +} + +type Worlds []models.World + +var messagePool = sync.Pool{ + New: func() any { + return new(Message) + }, +} + +var worldPool = sync.Pool{ + New: func() any { + return new(models.World) + }, +} + +var worldsPool = sync.Pool{ + New: func() any { + return make(Worlds, 0, 500) + }, +} + +func acquireMessage() *Message { + return messagePool.Get().(*Message) +} + +func releaseMessage(m *Message) { + m.Message = "" + messagePool.Put(m) +} + +func acquireWorld() *models.World { + return worldPool.Get().(*models.World) +} + +func releaseWorld(w *models.World) { + w.ID = 0 + w.RandomNumber = 0 + worldPool.Put(w) +} + +func acquireWorlds() Worlds { + return worldsPool.Get().(Worlds) +} + +func releaseWorlds(w Worlds) { + w = w[:0] + worldsPool.Put(w) +} + +func str2bytes(s string) []byte { + return unsafe.Slice(unsafe.StringData(s), len(s)) +} + +func initCache() { + worlds := acquireWorlds() + defer releaseWorlds(worlds) + + if err := facades.Orm().Query().Get(&worlds); err != nil { + panic(fmt.Sprintf("Failed to init cached Worlds: %v", err)) + } + + facades.Cache().Forever("worlds", worlds) +} + +func JSON(ctx http.Context, data any) { + ctx.Response().Header("Server", "Goravel") + ctx.Response().Header("Content-Type", contentTypeJson) + bytes, _ := sonic.Marshal(data) + _, _ = ctx.Response().Writer().Write(bytes) +} + +func Plaintext(ctx http.Context, data string) { + ctx.Response().Header("Server", "Goravel") + ctx.Response().Header("Content-Type", contentTypePlain) + _, _ = ctx.Response().Writer().Write(str2bytes(data)) +} diff --git a/frameworks/Go/goravel/src/gin/app/models/fortune.go b/frameworks/Go/goravel/src/gin/app/models/fortune.go new file mode 100644 index 00000000000..8e8e1dd21a8 --- /dev/null +++ b/frameworks/Go/goravel/src/gin/app/models/fortune.go @@ -0,0 +1,10 @@ +package models + +type Fortune struct { + ID uint `gorm:"primaryKey" json:"id"` + Message string `gorm:"column:message" json:"message"` +} + +func (r *Fortune) TableName() string { + return "Fortune" +} diff --git a/frameworks/Go/goravel/src/gin/app/models/world.go b/frameworks/Go/goravel/src/gin/app/models/world.go new file mode 100644 index 00000000000..da724366273 --- /dev/null +++ b/frameworks/Go/goravel/src/gin/app/models/world.go @@ -0,0 +1,10 @@ +package models + +type World struct { + ID int32 `gorm:"primaryKey" json:"id"` + RandomNumber int32 `gorm:"column:randomnumber" json:"randomNumber"` +} + +func (r *World) TableName() string { + return "World" +} diff --git a/frameworks/Go/goravel/src/gin/app/providers/route_service_provider.go b/frameworks/Go/goravel/src/gin/app/providers/route_service_provider.go new file mode 100644 index 00000000000..2e96015a24f --- /dev/null +++ b/frameworks/Go/goravel/src/gin/app/providers/route_service_provider.go @@ -0,0 +1,16 @@ +package providers + +import ( + "github.com/goravel/framework/contracts/foundation" + + "goravel/routes" +) + +type RouteServiceProvider struct{} + +func (receiver *RouteServiceProvider) Register(app foundation.Application) { +} + +func (receiver *RouteServiceProvider) Boot(app foundation.Application) { + routes.Web() +} diff --git a/frameworks/Go/goravel/src/gin/config/app.go b/frameworks/Go/goravel/src/gin/config/app.go new file mode 100644 index 00000000000..f6f898c90fd --- /dev/null +++ b/frameworks/Go/goravel/src/gin/config/app.go @@ -0,0 +1,40 @@ +package config + +import ( + "github.com/goravel/framework/cache" + "github.com/goravel/framework/console" + "github.com/goravel/framework/contracts/foundation" + "github.com/goravel/framework/database" + "github.com/goravel/framework/facades" + "github.com/goravel/framework/http" + "github.com/goravel/framework/log" + "github.com/goravel/framework/route" + "github.com/goravel/framework/validation" + "github.com/goravel/gin" + + "goravel/app/providers" +) + +// Boot Start all init methods of the current folder to bootstrap all config. +func Boot() {} + +func init() { + config := facades.Config() + config.Add("app", map[string]any{ + "name": "Goravel", + "env": "production", + "debug": false, + "key": config.Env("APP_KEY", ""), + "providers": []foundation.ServiceProvider{ + &log.ServiceProvider{}, + &console.ServiceProvider{}, + &database.ServiceProvider{}, + &cache.ServiceProvider{}, + &http.ServiceProvider{}, + &route.ServiceProvider{}, + &validation.ServiceProvider{}, + &providers.RouteServiceProvider{}, + &gin.ServiceProvider{}, + }, + }) +} diff --git a/frameworks/Go/goravel/src/gin/config/cache.go b/frameworks/Go/goravel/src/gin/config/cache.go new file mode 100644 index 00000000000..3c638243c2c --- /dev/null +++ b/frameworks/Go/goravel/src/gin/config/cache.go @@ -0,0 +1,18 @@ +package config + +import ( + "github.com/goravel/framework/facades" +) + +func init() { + config := facades.Config() + config.Add("cache", map[string]any{ + "default": "memory", + "stores": map[string]any{ + "memory": map[string]any{ + "driver": "memory", + }, + }, + "prefix": "goravel_cache", + }) +} diff --git a/frameworks/Go/goravel/src/gin/config/database.go b/frameworks/Go/goravel/src/gin/config/database.go new file mode 100644 index 00000000000..e1b1eb3272a --- /dev/null +++ b/frameworks/Go/goravel/src/gin/config/database.go @@ -0,0 +1,32 @@ +package config + +import ( + "github.com/goravel/framework/facades" +) + +func init() { + config := facades.Config() + config.Add("database", map[string]any{ + "default": "postgresql", + "connections": map[string]any{ + "postgresql": map[string]any{ + "driver": "postgresql", + "host": config.Env("DB_HOST", "tfb-database"), + "port": config.Env("DB_PORT", 5432), + "database": config.Env("DB_DATABASE", "hello_world"), + "username": config.Env("DB_USERNAME", "benchmarkdbuser"), + "password": config.Env("DB_PASSWORD", "benchmarkdbpass"), + "sslmode": "disable", + "timezone": "UTC", + "prefix": "", + "singular": true, + }, + }, + "pool": map[string]any{ + "max_idle_conns": 100, + "max_open_conns": 2000, + "conn_max_idletime": 3600, + "conn_max_lifetime": 3600, + }, + }) +} diff --git a/frameworks/Go/goravel/src/gin/config/http.go b/frameworks/Go/goravel/src/gin/config/http.go new file mode 100644 index 00000000000..9d8846ee610 --- /dev/null +++ b/frameworks/Go/goravel/src/gin/config/http.go @@ -0,0 +1,30 @@ +package config + +import ( + "github.com/gin-gonic/gin/render" + "github.com/goravel/framework/contracts/route" + "github.com/goravel/framework/facades" + "github.com/goravel/gin" + ginfacades "github.com/goravel/gin/facades" +) + +func init() { + config := facades.Config() + config.Add("http", map[string]any{ + "default": "gin", + "drivers": map[string]any{ + "gin": map[string]any{ + "body_limit": 4096, + "header_limit": 4096, + "route": func() (route.Route, error) { + return ginfacades.Route("gin"), nil + }, + "template": func() (render.HTMLRender, error) { + return gin.DefaultTemplate() + }, + }, + }, + "host": "", + "port": "8080", + }) +} diff --git a/frameworks/Go/goravel/src/gin/config/json.go b/frameworks/Go/goravel/src/gin/config/json.go new file mode 100644 index 00000000000..2b2e1af3f80 --- /dev/null +++ b/frameworks/Go/goravel/src/gin/config/json.go @@ -0,0 +1,31 @@ +package config + +import ( + "github.com/bytedance/sonic" + "github.com/goravel/framework/contracts/foundation" + "github.com/goravel/framework/facades" +) + +func init() { + facades.App().SetJson(NewJson()) +} + +type Json struct { + marshal func(any) ([]byte, error) + unmarshal func([]byte, any) error +} + +func NewJson() foundation.Json { + return &Json{ + marshal: sonic.Marshal, + unmarshal: sonic.Unmarshal, + } +} + +func (j *Json) Marshal(v any) ([]byte, error) { + return j.marshal(v) +} + +func (j *Json) Unmarshal(data []byte, v any) error { + return j.unmarshal(data, v) +} diff --git a/frameworks/Go/goravel/src/gin/go.mod b/frameworks/Go/goravel/src/gin/go.mod new file mode 100644 index 00000000000..93ac7f3ec4e --- /dev/null +++ b/frameworks/Go/goravel/src/gin/go.mod @@ -0,0 +1,194 @@ +module goravel + +go 1.22 + +require ( + github.com/bytedance/sonic v1.11.9 + github.com/gin-gonic/gin v1.10.0 + github.com/goravel/framework v1.14.1 + github.com/goravel/gin v1.2.1 +) + +require ( + atomicgo.dev/cursor v0.2.0 // indirect + atomicgo.dev/keyboard v0.2.9 // indirect + atomicgo.dev/schedule v0.1.0 // indirect + cloud.google.com/go v0.112.1 // indirect + cloud.google.com/go/compute v1.25.1 // indirect + cloud.google.com/go/compute/metadata v0.2.3 // indirect + cloud.google.com/go/iam v1.1.6 // indirect + cloud.google.com/go/pubsub v1.36.1 // indirect + filippo.io/edwards25519 v1.1.0 // indirect + github.com/Azure/go-autorest v14.2.0+incompatible // indirect + github.com/Azure/go-autorest/autorest/adal v0.9.16 // indirect + github.com/Azure/go-autorest/autorest/date v0.3.0 // indirect + github.com/Azure/go-autorest/logger v0.2.1 // indirect + github.com/Azure/go-autorest/tracing v0.6.0 // indirect + github.com/RichardKnop/logging v0.0.0-20190827224416-1a693bdd4fae // indirect + github.com/RichardKnop/machinery/v2 v2.0.13 // indirect + github.com/atotto/clipboard v0.1.4 // indirect + github.com/aws/aws-sdk-go v1.49.6 // indirect + github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect + github.com/bytedance/sonic/loader v0.1.1 // indirect + github.com/catppuccin/go v0.2.0 // indirect + github.com/cespare/xxhash/v2 v2.2.0 // indirect + github.com/charmbracelet/bubbles v0.18.0 // indirect + github.com/charmbracelet/bubbletea v0.26.3 // indirect + github.com/charmbracelet/huh v0.4.2 // indirect + github.com/charmbracelet/huh/spinner v0.0.0-20240508140610-13957916abf0 // indirect + github.com/charmbracelet/lipgloss v0.11.0 // indirect + github.com/charmbracelet/x/ansi v0.1.1 // indirect + github.com/charmbracelet/x/exp/strings v0.0.0-20240524151031-ff83003bf67a // indirect + github.com/charmbracelet/x/input v0.1.1 // indirect + github.com/charmbracelet/x/term v0.1.1 // indirect + github.com/charmbracelet/x/windows v0.1.2 // indirect + github.com/cloudwego/base64x v0.1.4 // indirect + github.com/cloudwego/iasm v0.2.0 // indirect + github.com/containerd/console v1.0.4-0.20230313162750-1ae8d489ac81 // indirect + github.com/cpuguy83/go-md2man/v2 v2.0.4 // indirect + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect + github.com/dustin/go-humanize v1.0.1 // indirect + github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f // indirect + github.com/felixge/httpsnoop v1.0.4 // indirect + github.com/fsnotify/fsnotify v1.7.0 // indirect + github.com/gabriel-vasile/mimetype v1.4.4 // indirect + github.com/gin-contrib/sse v0.1.0 // indirect + github.com/glebarez/go-sqlite v1.22.0 // indirect + github.com/glebarez/sqlite v1.11.0 // indirect + github.com/go-logr/logr v1.4.1 // indirect + github.com/go-logr/stdr v1.2.2 // indirect + github.com/go-playground/locales v0.14.1 // indirect + github.com/go-playground/universal-translator v0.18.1 // indirect + github.com/go-playground/validator/v10 v10.20.0 // indirect + github.com/go-redsync/redsync/v4 v4.8.1 // indirect + github.com/go-sql-driver/mysql v1.8.1 // indirect + github.com/go-stack/stack v1.8.0 // indirect + github.com/goccy/go-json v0.10.2 // indirect + github.com/golang-jwt/jwt/v4 v4.5.0 // indirect + github.com/golang-jwt/jwt/v5 v5.2.1 // indirect + github.com/golang-migrate/migrate/v4 v4.17.1 // indirect + github.com/golang-module/carbon/v2 v2.3.12 // indirect + github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 // indirect + github.com/golang-sql/sqlexp v0.1.0 // indirect + github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect + github.com/golang/protobuf v1.5.4 // indirect + github.com/golang/snappy v0.0.4 // indirect + github.com/gomodule/redigo v2.0.0+incompatible // indirect + github.com/google/s2a-go v0.1.7 // indirect + github.com/google/uuid v1.6.0 // indirect + github.com/google/wire v0.6.0 // indirect + github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect + github.com/googleapis/gax-go/v2 v2.12.3 // indirect + github.com/gookit/color v1.5.4 // indirect + github.com/gookit/filter v1.2.1 // indirect + github.com/gookit/goutil v0.6.15 // indirect + github.com/gookit/validate v1.5.2 // indirect + github.com/goravel/file-rotatelogs/v2 v2.4.2 // indirect + github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 // indirect + github.com/hashicorp/errwrap v1.1.0 // indirect + github.com/hashicorp/go-multierror v1.1.1 // indirect + github.com/hashicorp/hcl v1.0.0 // indirect + github.com/jackc/pgpassfile v1.0.0 // indirect + github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect + github.com/jackc/pgx/v5 v5.5.4 // indirect + github.com/jackc/puddle/v2 v2.2.1 // indirect + github.com/jinzhu/inflection v1.0.0 // indirect + github.com/jinzhu/now v1.1.5 // indirect + github.com/jmespath/go-jmespath v0.4.0 // indirect + github.com/json-iterator/go v1.1.12 // indirect + github.com/kelseyhightower/envconfig v1.4.0 // indirect + github.com/klauspost/compress v1.17.7 // indirect + github.com/klauspost/cpuid/v2 v2.2.8 // indirect + github.com/leodido/go-urn v1.4.0 // indirect + github.com/lib/pq v1.10.9 // indirect + github.com/lithammer/fuzzysearch v1.1.8 // indirect + github.com/lucasb-eyer/go-colorful v1.2.0 // indirect + github.com/magiconair/properties v1.8.7 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect + github.com/mattn/go-localereader v0.0.1 // indirect + github.com/mattn/go-runewidth v0.0.15 // indirect + github.com/microsoft/go-mssqldb v1.6.0 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect + github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 // indirect + github.com/muesli/cancelreader v0.2.2 // indirect + github.com/muesli/termenv v0.15.2 // indirect + github.com/opentracing/opentracing-go v1.2.0 // indirect + github.com/patrickmn/go-cache v2.1.0+incompatible // indirect + github.com/pelletier/go-toml/v2 v2.2.2 // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect + github.com/pterm/pterm v0.12.79 // indirect + github.com/rabbitmq/amqp091-go v1.9.0 // indirect + github.com/redis/go-redis/v9 v9.5.3 // indirect + github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect + github.com/rifflock/lfshook v0.0.0-20180920164130-b9218ef580f5 // indirect + github.com/rivo/uniseg v0.4.7 // indirect + github.com/robfig/cron/v3 v3.0.1 // indirect + github.com/rogpeppe/go-internal v1.11.0 // indirect + github.com/rotisserie/eris v0.5.4 // indirect + github.com/rs/cors v1.11.0 // indirect + github.com/russross/blackfriday/v2 v2.1.0 // indirect + github.com/sagikazarmark/locafero v0.4.0 // indirect + github.com/sagikazarmark/slog-shim v0.1.0 // indirect + github.com/savioxavier/termlink v1.3.0 // indirect + github.com/sirupsen/logrus v1.9.3 // indirect + github.com/sourcegraph/conc v0.3.0 // indirect + github.com/spf13/afero v1.11.0 // indirect + github.com/spf13/cast v1.6.0 // indirect + github.com/spf13/pflag v1.0.5 // indirect + github.com/spf13/viper v1.19.0 // indirect + github.com/stretchr/objx v0.5.2 // indirect + github.com/stretchr/testify v1.9.0 // indirect + github.com/subosito/gotenv v1.6.0 // indirect + github.com/twitchyliquid64/golang-asm v0.15.1 // indirect + github.com/ugorji/go/codec v1.2.12 // indirect + github.com/unrolled/secure v1.14.0 // indirect + github.com/urfave/cli/v2 v2.27.2 // indirect + github.com/xdg-go/pbkdf2 v1.0.0 // indirect + github.com/xdg-go/scram v1.1.1 // indirect + github.com/xdg-go/stringprep v1.0.3 // indirect + github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect + github.com/xrash/smetrics v0.0.0-20240312152122-5f08fbb34913 // indirect + github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d // indirect + go.mongodb.org/mongo-driver v1.7.5 // indirect + go.opencensus.io v0.24.0 // indirect + go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0 // indirect + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 // indirect + go.opentelemetry.io/otel v1.24.0 // indirect + go.opentelemetry.io/otel/metric v1.24.0 // indirect + go.opentelemetry.io/otel/trace v1.24.0 // indirect + go.uber.org/atomic v1.11.0 // indirect + go.uber.org/multierr v1.9.0 // indirect + golang.org/x/arch v0.8.0 // indirect + golang.org/x/crypto v0.24.0 // indirect + golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect + golang.org/x/net v0.25.0 // indirect + golang.org/x/oauth2 v0.18.0 // indirect + golang.org/x/sync v0.7.0 // indirect + golang.org/x/sys v0.21.0 // indirect + golang.org/x/term v0.21.0 // indirect + golang.org/x/text v0.16.0 // indirect + golang.org/x/time v0.5.0 // indirect + google.golang.org/api v0.171.0 // indirect + google.golang.org/appengine v1.6.8 // indirect + google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20240318140521-94a12d6c2237 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237 // indirect + google.golang.org/grpc v1.64.0 // indirect + google.golang.org/protobuf v1.34.1 // indirect + gopkg.in/ini.v1 v1.67.0 // indirect + gopkg.in/yaml.v2 v2.4.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect + gorm.io/driver/mysql v1.5.6 // indirect + gorm.io/driver/postgres v1.5.7 // indirect + gorm.io/driver/sqlserver v1.5.3 // indirect + gorm.io/gorm v1.25.10 // indirect + gorm.io/plugin/dbresolver v1.5.1 // indirect + modernc.org/libc v1.37.6 // indirect + modernc.org/mathutil v1.6.0 // indirect + modernc.org/memory v1.7.2 // indirect + modernc.org/sqlite v1.28.0 // indirect +) diff --git a/frameworks/Go/goravel/src/gin/go.sum b/frameworks/Go/goravel/src/gin/go.sum new file mode 100644 index 00000000000..92b222fbcbb --- /dev/null +++ b/frameworks/Go/goravel/src/gin/go.sum @@ -0,0 +1,1170 @@ +atomicgo.dev/assert v0.0.2 h1:FiKeMiZSgRrZsPo9qn/7vmr7mCsh5SZyXY4YGYiYwrg= +atomicgo.dev/assert v0.0.2/go.mod h1:ut4NcI3QDdJtlmAxQULOmA13Gz6e2DWbSAS8RUOmNYQ= +atomicgo.dev/cursor v0.2.0 h1:H6XN5alUJ52FZZUkI7AlJbUc1aW38GWZalpYRPpoPOw= +atomicgo.dev/cursor v0.2.0/go.mod h1:Lr4ZJB3U7DfPPOkbH7/6TOtJ4vFGHlgj1nc+n900IpU= +atomicgo.dev/keyboard v0.2.9 h1:tOsIid3nlPLZ3lwgG8KZMp/SFmr7P0ssEN5JUsm78K8= +atomicgo.dev/keyboard v0.2.9/go.mod h1:BC4w9g00XkxH/f1HXhW2sXmJFOCWbKn9xrOunSFtExQ= +atomicgo.dev/schedule v0.1.0 h1:nTthAbhZS5YZmgYbb2+DH8uQIZcTlIrd4eYr3UQxEjs= +atomicgo.dev/schedule v0.1.0/go.mod h1:xeUa3oAkiuHYh8bKiQBRojqAMq3PXXbJujjb0hw8pEU= +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= +cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= +cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= +cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= +cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= +cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= +cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= +cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= +cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= +cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= +cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= +cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= +cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= +cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= +cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= +cloud.google.com/go v0.75.0/go.mod h1:VGuuCn7PG0dwsd5XPVm2Mm3wlh3EL55/79EKB6hlPTY= +cloud.google.com/go v0.112.1 h1:uJSeirPke5UNZHIb4SxfZklVSiWWVqW4oXlETwZziwM= +cloud.google.com/go v0.112.1/go.mod h1:+Vbu+Y1UU+I1rjmzeMOb/8RfkKJK2Gyxi1X6jJCZLo4= +cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= +cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= +cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= +cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= +cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= +cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= +cloud.google.com/go/compute v1.25.1 h1:ZRpHJedLtTpKgr3RV1Fx23NuaAEN1Zfx9hw1u4aJdjU= +cloud.google.com/go/compute v1.25.1/go.mod h1:oopOIR53ly6viBYxaDhBfJwzUAxf1zE//uf3IB011ls= +cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY= +cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= +cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= +cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= +cloud.google.com/go/iam v1.1.6 h1:bEa06k05IO4f4uJonbB5iAgKTPpABy1ayxaIZV/GHVc= +cloud.google.com/go/iam v1.1.6/go.mod h1:O0zxdPeGBoFdWW3HWmBxJsk0pfvNM/p/qa82rWOGTwI= +cloud.google.com/go/kms v1.15.7 h1:7caV9K3yIxvlQPAcaFffhlT7d1qpxjB1wHBtjWa13SM= +cloud.google.com/go/kms v1.15.7/go.mod h1:ub54lbsa6tDkUwnu4W7Yt1aAIFLnspgh0kPGToDukeI= +cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= +cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= +cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= +cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= +cloud.google.com/go/pubsub v1.10.0/go.mod h1:eNpTrkOy7dCpkNyaSNetMa6udbgecJMd0ZsTJS/cuNo= +cloud.google.com/go/pubsub v1.36.1 h1:dfEPuGCHGbWUhaMCTHUFjfroILEkx55iUmKBZTP5f+Y= +cloud.google.com/go/pubsub v1.36.1/go.mod h1:iYjCa9EzWOoBiTdd4ps7QoMtMln5NwaZQpK1hbRfBDE= +cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= +cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= +cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= +cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= +cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= +dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= +filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.4.0/go.mod h1:ON4tFdPTwRcgWEaVDrN3584Ef+b7GgSJaXxe5fW9t4M= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.6.0/go.mod h1:bjGvMhVMb+EEm3VRNQawDMUyMMjo+S5ewNjflkep/0Q= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.6.1/go.mod h1:bjGvMhVMb+EEm3VRNQawDMUyMMjo+S5ewNjflkep/0Q= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.7.1 h1:/iHxaJhsFr0+xVFfbMr5vxz848jyiWuIEDhYq3y5odY= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.7.1/go.mod h1:bjGvMhVMb+EEm3VRNQawDMUyMMjo+S5ewNjflkep/0Q= +github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.3.0 h1:vcYCAze6p19qBW7MhZybIsqD8sMV8js0NyQM8JDnVtg= +github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.3.0/go.mod h1:OQeznEEkTZ9OrhHJoDD8ZDq51FHgXjqtP9z6bEwBq9U= +github.com/Azure/azure-sdk-for-go/sdk/internal v1.1.2/go.mod h1:eWRD7oawr1Mu1sLCawqVc0CUiF43ia3qQMxLscsKQ9w= +github.com/Azure/azure-sdk-for-go/sdk/internal v1.2.0/go.mod h1:eWRD7oawr1Mu1sLCawqVc0CUiF43ia3qQMxLscsKQ9w= +github.com/Azure/azure-sdk-for-go/sdk/internal v1.3.0 h1:sXr+ck84g/ZlZUOZiNELInmMgOsuGwdjjVkEIde0OtY= +github.com/Azure/azure-sdk-for-go/sdk/internal v1.3.0/go.mod h1:okt5dMMTOFjX/aovMlrjvvXoPMBVSPzk9185BT0+eZM= +github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azkeys v1.0.0 h1:yfJe15aSwEQ6Oo6J+gdfdulPNoZ3TEhmbhLIoxZcA+U= +github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azkeys v1.0.0/go.mod h1:Q28U+75mpCaSCDowNEmhIo/rmgdkqmkmzI7N6TGR4UY= +github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v0.8.0 h1:T028gtTPiYt/RMUfs8nVsAL7FDQrfLlrm/NnRG/zcC4= +github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v0.8.0/go.mod h1:cw4zVQgBby0Z5f2v0itn6se2dDP17nTjbZFXW5uPyHA= +github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25UVaW/CKtUDjefjrs0SPonmDGUVOYP0= +github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= +github.com/Azure/go-autorest v14.2.0+incompatible h1:V5VMDjClD3GiElqLWO7mz2MxNAK/vTfRHdAubSIPRgs= +github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= +github.com/Azure/go-autorest/autorest/adal v0.9.16 h1:P8An8Z9rH1ldbOLdFpxYorgOt2sywL9V24dAwWHPuGc= +github.com/Azure/go-autorest/autorest/adal v0.9.16/go.mod h1:tGMin8I49Yij6AQ+rvV+Xa/zwxYQB5hmsd6DkfAx2+A= +github.com/Azure/go-autorest/autorest/date v0.3.0 h1:7gUk1U5M/CQbp9WoqinNzJar+8KY+LPI6wiWrP/myHw= +github.com/Azure/go-autorest/autorest/date v0.3.0/go.mod h1:BI0uouVdmngYNUzGWeSYnokU+TrmwEsOqdt8Y6sso74= +github.com/Azure/go-autorest/autorest/mocks v0.4.1 h1:K0laFcLE6VLTOwNgSxaGbUcLPuGXlNkbVvq4cW4nIHk= +github.com/Azure/go-autorest/autorest/mocks v0.4.1/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k= +github.com/Azure/go-autorest/logger v0.2.1 h1:IG7i4p/mDa2Ce4TRyAO8IHnVhAVF3RFU+ZtXWSmf4Tg= +github.com/Azure/go-autorest/logger v0.2.1/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8= +github.com/Azure/go-autorest/tracing v0.6.0 h1:TYi4+3m5t6K48TGI9AUdb+IzbnSxvnvUMfuitfgcfuo= +github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU= +github.com/AzureAD/microsoft-authentication-library-for-go v1.0.0/go.mod h1:kgDmCTgBzIEPFElEF+FK0SdjAor06dRq2Go927dnQ6o= +github.com/AzureAD/microsoft-authentication-library-for-go v1.1.0 h1:HCc0+LpPfpCKs6LGGLAhwBARt9632unrVcI6i8s/8os= +github.com/AzureAD/microsoft-authentication-library-for-go v1.1.0/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/MarvinJWendt/testza v0.1.0/go.mod h1:7AxNvlfeHP7Z/hDQ5JtE3OKYT3XFUeLCDE2DQninSqs= +github.com/MarvinJWendt/testza v0.2.1/go.mod h1:God7bhG8n6uQxwdScay+gjm9/LnO4D3kkcZX4hv9Rp8= +github.com/MarvinJWendt/testza v0.2.8/go.mod h1:nwIcjmr0Zz+Rcwfh3/4UhBp7ePKVhuBExvZqnKYWlII= +github.com/MarvinJWendt/testza v0.2.10/go.mod h1:pd+VWsoGUiFtq+hRKSU1Bktnn+DMCSrDrXDpX2bG66k= +github.com/MarvinJWendt/testza v0.2.12/go.mod h1:JOIegYyV7rX+7VZ9r77L/eH6CfJHHzXjB69adAhzZkI= +github.com/MarvinJWendt/testza v0.3.0/go.mod h1:eFcL4I0idjtIx8P9C6KkAuLgATNKpX4/2oUqKc6bF2c= +github.com/MarvinJWendt/testza v0.4.2/go.mod h1:mSdhXiKH8sg/gQehJ63bINcCKp7RtYewEjXsvsVUPbE= +github.com/MarvinJWendt/testza v0.5.2 h1:53KDo64C1z/h/d/stCYCPY69bt/OSwjq5KpFNwi+zB4= +github.com/MarvinJWendt/testza v0.5.2/go.mod h1:xu53QFE5sCdjtMCKk8YMQ2MnymimEctc4n3EjyIYvEY= +github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow= +github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= +github.com/RichardKnop/logging v0.0.0-20190827224416-1a693bdd4fae h1:DcFpTQBYQ9Ct2d6sC7ol0/ynxc2pO1cpGUM+f4t5adg= +github.com/RichardKnop/logging v0.0.0-20190827224416-1a693bdd4fae/go.mod h1:rJJ84PyA/Wlmw1hO+xTzV2wsSUon6J5ktg0g8BF2PuU= +github.com/RichardKnop/machinery/v2 v2.0.13 h1:uo9htg+qNBi7UeUK3jcTBl3vTO/vvLKGaOdCOKePl50= +github.com/RichardKnop/machinery/v2 v2.0.13/go.mod h1:Yc2X/QRm9rRfAjB+93NGR+kSUqtnqqs8kME4L+TKKiw= +github.com/atomicgo/cursor v0.0.1/go.mod h1:cBON2QmmrysudxNBFthvMtN32r3jxVRIvzkUiF/RuIk= +github.com/atotto/clipboard v0.1.4 h1:EH0zSVneZPSuFR11BlR9YppQTVDbh5+16AmcJi4g1z4= +github.com/atotto/clipboard v0.1.4/go.mod h1:ZY9tmq7sm5xIbd9bOK4onWV4S6X0u6GY7Vn0Yu86PYI= +github.com/aws/aws-sdk-go v1.34.28/go.mod h1:H7NKnBqNVzoTJpGfLrQkkD+ytBA93eiDYi/+8rV9s48= +github.com/aws/aws-sdk-go v1.37.16/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= +github.com/aws/aws-sdk-go v1.49.6 h1:yNldzF5kzLBRvKlKz1S0bkvc2+04R1kt13KfBWQBfFA= +github.com/aws/aws-sdk-go v1.49.6/go.mod h1:LF8svs817+Nz+DmiMQKTO3ubZ/6IaTpq3TjupRn3Eqk= +github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k= +github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8= +github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= +github.com/bradfitz/gomemcache v0.0.0-20190913173617-a41fca850d0b/go.mod h1:H0wQNHz2YrLsuXOZozoeDmnHXkNCRmMW0gwFWDfEZDA= +github.com/brianvoe/gofakeit/v6 v6.28.0 h1:Xib46XXuQfmlLS2EXRuJpqcw8St6qSZz75OUo0tgAW4= +github.com/brianvoe/gofakeit/v6 v6.28.0/go.mod h1:Xj58BMSnFqcn/fAQeSK+/PLtC5kSb7FJIq4JyGa8vEs= +github.com/bsm/ginkgo/v2 v2.5.0/go.mod h1:AiKlXPm7ItEHNc/2+OkrNG4E0ITzojb9/xWzvQ9XZ9w= +github.com/bsm/ginkgo/v2 v2.7.0/go.mod h1:AiKlXPm7ItEHNc/2+OkrNG4E0ITzojb9/xWzvQ9XZ9w= +github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs= +github.com/bsm/ginkgo/v2 v2.12.0/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdbAV9g4c= +github.com/bsm/gomega v1.20.0/go.mod h1:JifAceMQ4crZIWYUKrlGcmbN3bqHogVTADMD2ATsbwk= +github.com/bsm/gomega v1.26.0/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0= +github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA= +github.com/bsm/gomega v1.27.10/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0= +github.com/bytedance/sonic v1.11.9 h1:LFHENlIY/SLzDWverzdOvgMztTxcfcF+cqNsz9pK5zg= +github.com/bytedance/sonic v1.11.9/go.mod h1:LysEHSvpvDySVdC2f87zGWf6CIKJcAvqab1ZaiQtds4= +github.com/bytedance/sonic/loader v0.1.1 h1:c+e5Pt1k/cy5wMveRDyk2X4B9hF4g7an8N3zCYjJFNM= +github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU= +github.com/catppuccin/go v0.2.0 h1:ktBeIrIP42b/8FGiScP9sgrWOss3lw0Z5SktRoithGA= +github.com/catppuccin/go v0.2.0/go.mod h1:8IHJuMGaUUjQM82qBrGNBv7LFq6JI3NnQCF6MOlZjpc= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= +github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/charmbracelet/bubbles v0.18.0 h1:PYv1A036luoBGroX6VWjQIE9Syf2Wby2oOl/39KLfy0= +github.com/charmbracelet/bubbles v0.18.0/go.mod h1:08qhZhtIwzgrtBjAcJnij1t1H0ZRjwHyGsy6AL11PSw= +github.com/charmbracelet/bubbletea v0.26.3 h1:iXyGvI+FfOWqkB2V07m1DF3xxQijxjY2j8PqiXYqasg= +github.com/charmbracelet/bubbletea v0.26.3/go.mod h1:bpZHfDHTYJC5g+FBK+ptJRCQotRC+Dhh3AoMxa/2+3Q= +github.com/charmbracelet/huh v0.4.2 h1:5wLkwrA58XDAfEZsJzNQlfJ+K8N9+wYwvR5FOM7jXFM= +github.com/charmbracelet/huh v0.4.2/go.mod h1:g9OXBgtY3zRV4ahnVih9bZE+1yGYN+y2C9Q6L2P+WM0= +github.com/charmbracelet/huh/spinner v0.0.0-20240508140610-13957916abf0 h1:79JTuYRirtyCn9ac6rzPt5AQKtBDFc1gKxpw0wBrI+Y= +github.com/charmbracelet/huh/spinner v0.0.0-20240508140610-13957916abf0/go.mod h1:Zxt9FH6togK9kY71pRJGtmyNkJ1eIWdK1gRaXrS/FKA= +github.com/charmbracelet/lipgloss v0.11.0 h1:UoAcbQ6Qml8hDwSWs0Y1cB5TEQuZkDPH/ZqwWWYTG4g= +github.com/charmbracelet/lipgloss v0.11.0/go.mod h1:1UdRTH9gYgpcdNN5oBtjbu/IzNKtzVtb7sqN1t9LNn8= +github.com/charmbracelet/x/ansi v0.1.1 h1:CGAduulr6egay/YVbGc8Hsu8deMg1xZ/bkaXTPi1JDk= +github.com/charmbracelet/x/ansi v0.1.1/go.mod h1:dk73KoMTT5AX5BsX0KrqhsTqAnhZZoCBjs7dGWp4Ktw= +github.com/charmbracelet/x/exp/strings v0.0.0-20240524151031-ff83003bf67a h1:lOpqe2UvPmlln41DGoii7wlSZ/q8qGIon5JJ8Biu46I= +github.com/charmbracelet/x/exp/strings v0.0.0-20240524151031-ff83003bf67a/go.mod h1:pBhA0ybfXv6hDjQUZ7hk1lVxBiUbupdw5R31yPUViVQ= +github.com/charmbracelet/x/exp/term v0.0.0-20240524151031-ff83003bf67a h1:k/s6UoOSVynWiw7PlclyGO2VdVs5ZLbMIHiGp4shFZE= +github.com/charmbracelet/x/exp/term v0.0.0-20240524151031-ff83003bf67a/go.mod h1:YBotIGhfoWhHDlnUpJMkjebGV2pdGRCn1Y4/Nk/vVcU= +github.com/charmbracelet/x/input v0.1.1 h1:YDOJaTUKCqtGnq9PHzx3pkkl4pXDOANUHmhH3DqMtM4= +github.com/charmbracelet/x/input v0.1.1/go.mod h1:jvdTVUnNWj/RD6hjC4FsoB0SeZCJ2ZBkiuFP9zXvZI0= +github.com/charmbracelet/x/term v0.1.1 h1:3cosVAiPOig+EV4X9U+3LDgtwwAoEzJjNdwbXDjF6yI= +github.com/charmbracelet/x/term v0.1.1/go.mod h1:wB1fHt5ECsu3mXYusyzcngVWWlu1KKUmmLhfgr/Flxw= +github.com/charmbracelet/x/windows v0.1.2 h1:Iumiwq2G+BRmgoayww/qfcvof7W/3uLoelhxojXlRWg= +github.com/charmbracelet/x/windows v0.1.2/go.mod h1:GLEO/l+lizvFDBPLIOk+49gdX49L9YWMB5t+DZd0jkQ= +github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cloudwego/base64x v0.1.4 h1:jwCgWpFanWmN8xoIUHa2rtzmkd5J2plF/dnLS6Xd/0Y= +github.com/cloudwego/base64x v0.1.4/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w= +github.com/cloudwego/iasm v0.2.0 h1:1KNIy1I1H9hNNFEEH3DVnI4UujN+1zjpuk6gwHLTssg= +github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY= +github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= +github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/containerd/console v1.0.3/go.mod h1:7LqA/THxQ86k76b8c/EMSiaJ3h1eZkMkXar0TQ1gf3U= +github.com/containerd/console v1.0.4-0.20230313162750-1ae8d489ac81 h1:q2hJAaP1k2wIvVRd/hEHD7lacgqrCPS+k8g1MndzfWY= +github.com/containerd/console v1.0.4-0.20230313162750-1ae8d489ac81/go.mod h1:YynlIjWYF8myEu6sdkwKIvGQq+cOckRm6So2avqoYAk= +github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/cpuguy83/go-md2man/v2 v2.0.4 h1:wfIWP927BUkWJb2NmU/kNDYIBTh/ziUX91+lVfRxZq4= +github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= +github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= +github.com/dhui/dktest v0.4.1 h1:/w+IWuDXVymg3IrRJCHHOkMK10m9aNVMOyD0X12YVTg= +github.com/dhui/dktest v0.4.1/go.mod h1:DdOqcUpL7vgyP4GlF3X3w7HbSlz8cEQzwewPveYEQbA= +github.com/dnaeon/go-vcr v1.1.0/go.mod h1:M7tiix8f0r6mKKJ3Yq/kqU1OYf3MnfmBWVbPx/yU9ko= +github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ= +github.com/docker/distribution v2.8.2+incompatible h1:T3de5rq0dB1j30rp0sA2rER+m322EBzniBPB6ZIzuh8= +github.com/docker/distribution v2.8.2+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= +github.com/docker/docker v24.0.9+incompatible h1:HPGzNmwfLZWdxHqK9/II92pyi1EpYKsAqcl4G0Of9v0= +github.com/docker/docker v24.0.9+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ= +github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= +github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= +github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= +github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= +github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= +github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= +github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f h1:Y/CXytFA4m6baUTXGLOoWe4PQhGxaX0KpnayAqC48p4= +github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f/go.mod h1:vw97MGsxSvLiUE2X8qFplwetxpGLQrlU1Q9AUEIzCaM= +github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= +github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= +github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= +github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= +github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= +github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= +github.com/gabriel-vasile/mimetype v1.4.4 h1:QjV6pZ7/XZ7ryI2KuyeEDE8wnh7fHP9YnQy+R0LnH8I= +github.com/gabriel-vasile/mimetype v1.4.4/go.mod h1:JwLei5XPtWdGiMFB5Pjle1oEeoSeEuJfJE+TtfvdB/s= +github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= +github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= +github.com/gin-gonic/gin v1.10.0 h1:nTuyha1TYqgedzytsKYqna+DfLos46nTv2ygFy86HFU= +github.com/gin-gonic/gin v1.10.0/go.mod h1:4PMNQiOhvDRa013RKVbsiNwoyezlm2rm0uX/T7kzp5Y= +github.com/glebarez/go-sqlite v1.22.0 h1:uAcMJhaA6r3LHMTFgP0SifzgXg46yJkgxqyuyec+ruQ= +github.com/glebarez/go-sqlite v1.22.0/go.mod h1:PlBIdHe0+aUEFn+r2/uthrWq4FxbzugL0L8Li6yQJbc= +github.com/glebarez/sqlite v1.11.0 h1:wSG0irqzP6VurnMEpFGer5Li19RpIRi2qvQz++w0GMw= +github.com/glebarez/sqlite v1.11.0/go.mod h1:h8/o8j5wiAsqSPoWELDUdJXhjAhsVliSn7bWZjOhrgQ= +github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= +github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= +github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ= +github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= +github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= +github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= +github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= +github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= +github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= +github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= +github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= +github.com/go-playground/validator/v10 v10.20.0 h1:K9ISHbSaI0lyB2eWMPJo+kOS/FBExVwjEviJTixqxL8= +github.com/go-playground/validator/v10 v10.20.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM= +github.com/go-redis/redis v6.15.9+incompatible h1:K0pv1D7EQUjfyoMql+r/jZqCLizCGKFlFgcHWWmHQjg= +github.com/go-redis/redis v6.15.9+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA= +github.com/go-redis/redis/v7 v7.4.0 h1:7obg6wUoj05T0EpY0o8B59S9w5yeMWql7sw2kwNW1x4= +github.com/go-redis/redis/v7 v7.4.0/go.mod h1:JDNMw23GTyLNC4GZu9njt15ctBQVn7xjRfnwdHj/Dcg= +github.com/go-redis/redis/v8 v8.11.4/go.mod h1:2Z2wHZXdQpCDXEGzqMockDpNyYvi2l4Pxt6RJr792+w= +github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC0oI= +github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo= +github.com/go-redsync/redsync/v4 v4.8.1 h1:rq2RvdTI0obznMdxKUWGdmmulo7lS9yCzb8fgDKOlbM= +github.com/go-redsync/redsync/v4 v4.8.1/go.mod h1:LmUAsQuQxhzZAoGY7JS6+dNhNmZyonMZiiEDY9plotM= +github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= +github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= +github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI= +github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y= +github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg= +github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= +github.com/gobuffalo/attrs v0.0.0-20190224210810-a9411de4debd/go.mod h1:4duuawTqi2wkkpB4ePgWMaai6/Kc6WEz83bhFwpHzj0= +github.com/gobuffalo/depgen v0.0.0-20190329151759-d478694a28d3/go.mod h1:3STtPUQYuzV0gBVOY3vy6CfMm/ljR4pABfrTeHNLHUY= +github.com/gobuffalo/depgen v0.1.0/go.mod h1:+ifsuy7fhi15RWncXQQKjWS9JPkdah5sZvtHc2RXGlg= +github.com/gobuffalo/envy v1.6.15/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI= +github.com/gobuffalo/envy v1.7.0/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI= +github.com/gobuffalo/flect v0.1.0/go.mod h1:d2ehjJqGOH/Kjqcoz+F7jHTBbmDb38yXA598Hb50EGs= +github.com/gobuffalo/flect v0.1.1/go.mod h1:8JCgGVbRjJhVgD6399mQr4fx5rRfGKVzFjbj6RE/9UI= +github.com/gobuffalo/flect v0.1.3/go.mod h1:8JCgGVbRjJhVgD6399mQr4fx5rRfGKVzFjbj6RE/9UI= +github.com/gobuffalo/genny v0.0.0-20190329151137-27723ad26ef9/go.mod h1:rWs4Z12d1Zbf19rlsn0nurr75KqhYp52EAGGxTbBhNk= +github.com/gobuffalo/genny v0.0.0-20190403191548-3ca520ef0d9e/go.mod h1:80lIj3kVJWwOrXWWMRzzdhW3DsrdjILVil/SFKBzF28= +github.com/gobuffalo/genny v0.1.0/go.mod h1:XidbUqzak3lHdS//TPu2OgiFB+51Ur5f7CSnXZ/JDvo= +github.com/gobuffalo/genny v0.1.1/go.mod h1:5TExbEyY48pfunL4QSXxlDOmdsD44RRq4mVZ0Ex28Xk= +github.com/gobuffalo/gitgen v0.0.0-20190315122116-cc086187d211/go.mod h1:vEHJk/E9DmhejeLeNt7UVvlSGv3ziL+djtTr3yyzcOw= +github.com/gobuffalo/gogen v0.0.0-20190315121717-8f38393713f5/go.mod h1:V9QVDIxsgKNZs6L2IYiGR8datgMhB577vzTDqypH360= +github.com/gobuffalo/gogen v0.1.0/go.mod h1:8NTelM5qd8RZ15VjQTFkAW6qOMx5wBbW4dSCS3BY8gg= +github.com/gobuffalo/gogen v0.1.1/go.mod h1:y8iBtmHmGc4qa3urIyo1shvOD8JftTtfcKi+71xfDNE= +github.com/gobuffalo/logger v0.0.0-20190315122211-86e12af44bc2/go.mod h1:QdxcLw541hSGtBnhUc4gaNIXRjiDppFGaDqzbrBd3v8= +github.com/gobuffalo/mapi v1.0.1/go.mod h1:4VAGh89y6rVOvm5A8fKFxYG+wIW6LO1FMTG9hnKStFc= +github.com/gobuffalo/mapi v1.0.2/go.mod h1:4VAGh89y6rVOvm5A8fKFxYG+wIW6LO1FMTG9hnKStFc= +github.com/gobuffalo/packd v0.0.0-20190315124812-a385830c7fc0/go.mod h1:M2Juc+hhDXf/PnmBANFCqx4DM3wRbgDvnVWeG2RIxq4= +github.com/gobuffalo/packd v0.1.0/go.mod h1:M2Juc+hhDXf/PnmBANFCqx4DM3wRbgDvnVWeG2RIxq4= +github.com/gobuffalo/packr/v2 v2.0.9/go.mod h1:emmyGweYTm6Kdper+iywB6YK5YzuKchGtJQZ0Odn4pQ= +github.com/gobuffalo/packr/v2 v2.2.0/go.mod h1:CaAwI0GPIAv+5wKLtv8Afwl+Cm78K/I/VCm/3ptBN+0= +github.com/gobuffalo/syncx v0.0.0-20190224160051-33c29581e754/go.mod h1:HhnNqWY95UYwwW3uSASeV7vtgYkT2t16hJgV3AEPUpw= +github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= +github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= +github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang-jwt/jwt/v4 v4.0.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= +github.com/golang-jwt/jwt/v4 v4.4.3/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= +github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg= +github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= +github.com/golang-jwt/jwt/v5 v5.0.0/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= +github.com/golang-jwt/jwt/v5 v5.2.1 h1:OuVbFODueb089Lh128TAcimifWaLhJwVflnrgM17wHk= +github.com/golang-jwt/jwt/v5 v5.2.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= +github.com/golang-migrate/migrate/v4 v4.17.1 h1:4zQ6iqL6t6AiItphxJctQb3cFqWiSpMnX7wLTPnnYO4= +github.com/golang-migrate/migrate/v4 v4.17.1/go.mod h1:m8hinFyWBn0SA4QKHuKh175Pm9wjmxj3S2Mia7dbXzM= +github.com/golang-module/carbon/v2 v2.3.12 h1:VC1DwN1kBwJkh5MjXmTFryjs5g4CWyoM8HAHffZPX/k= +github.com/golang-module/carbon/v2 v2.3.12/go.mod h1:HNsedGzXGuNciZImYP2OMnpiwq/vhIstR/vn45ib5cI= +github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 h1:au07oEsX2xN0ktxqI+Sida1w446QrXBRJ0nee3SNZlA= +github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= +github.com/golang-sql/sqlexp v0.1.0 h1:ZCD6MBpcuOVfGVqsEmY5/4FtYiKz6tSyUv9LPEDei6A= +github.com/golang-sql/sqlexp v0.1.0/go.mod h1:J4ad9Vo8ZCWQ2GMrC4UCQy1JpCbwU9m3EOqtpKwwwHI= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= +github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= +github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= +github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= +github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/gomodule/redigo v1.8.2/go.mod h1:P9dn9mFrCBvWhGE1wpxx6fgq7BAeLBk+UUUzlpkBYO0= +github.com/gomodule/redigo v1.9.2/go.mod h1:KsU3hiK/Ay8U42qpaJk+kuNa3C+spxapWpM+ywhcgtw= +github.com/gomodule/redigo v2.0.0+incompatible h1:K/R+8tc58AaqLkqG2Ol3Qk+DR/TlNuhuh457pBFPtt0= +github.com/gomodule/redigo v2.0.0+incompatible/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4= +github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= +github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26 h1:Xim43kblpZXfIBQsbuBVKCudVG457BR2GZFIz3uw3hQ= +github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26/go.mod h1:dDKJzRmX4S37WGHujM7tX//fmj1uioxKzKxz3lo4HJo= +github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/s2a-go v0.1.7 h1:60BLSyTrOV4/haCDW4zb1guZItoSq8foHCXrAnjBo/o= +github.com/google/s2a-go v0.1.7/go.mod h1:50CgR4k1jNlWBu4UfS4AcfhVe1r6pdZPygJ3R8F0Qdw= +github.com/google/subcommands v1.2.0/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk= +github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/wire v0.6.0 h1:HBkoIh4BdSxoyo9PveV8giw7ZsaBOvzWKfcg/6MrVwI= +github.com/google/wire v0.6.0/go.mod h1:F4QhpQ9EDIdJ1Mbop/NZBRB+5yrR6qg3BnctaoUk6NA= +github.com/googleapis/enterprise-certificate-proxy v0.3.2 h1:Vie5ybvEvT75RniqhfFxPRy3Bf7vr3h0cechB90XaQs= +github.com/googleapis/enterprise-certificate-proxy v0.3.2/go.mod h1:VLSiSSBs/ksPL8kq3OBOQ6WRI2QnaFynd1DCjZ62+V0= +github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= +github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= +github.com/googleapis/gax-go/v2 v2.12.3 h1:5/zPPDvw8Q1SuXjrqrZslrqT7dL/uJT2CQii/cLCKqA= +github.com/googleapis/gax-go/v2 v2.12.3/go.mod h1:AKloxT6GtNbaLm8QTNSidHUVsHYcBHwWRvkNFJUQcS4= +github.com/gookit/color v1.4.2/go.mod h1:fqRyamkC1W8uxl+lxCQxOT09l/vYfZ+QeiX3rKQHCoQ= +github.com/gookit/color v1.5.0/go.mod h1:43aQb+Zerm/BWh2GnrgOQm7ffz7tvQXEKV6BFMl7wAo= +github.com/gookit/color v1.5.4 h1:FZmqs7XOyGgCAxmWyPslpiok1k05wmY3SJTytgvYFs0= +github.com/gookit/color v1.5.4/go.mod h1:pZJOeOS8DM43rXbp4AZo1n9zCU2qjpcRko0b6/QJi9w= +github.com/gookit/filter v1.2.1 h1:37XivkBm2E5qe1KaGdJ5ZfF5l9NYdGWfLEeQadJD8O4= +github.com/gookit/filter v1.2.1/go.mod h1:rxynQFr793x+XDwnRmJFEb53zDw0Zqx3OD7TXWoR9mQ= +github.com/gookit/goutil v0.6.15 h1:mMQ0ElojNZoyPD0eVROk5QXJPh2uKR4g06slgPDF5Jo= +github.com/gookit/goutil v0.6.15/go.mod h1:qdKdYEHQdEtyH+4fNdQNZfJHhI0jUZzHxQVAV3DaMDY= +github.com/gookit/validate v1.5.2 h1:i5I2OQ7WYHFRPRATGu9QarR9snnNHydvwSuHXaRWAV0= +github.com/gookit/validate v1.5.2/go.mod h1:yuPy2WwDlwGRa06fFJ5XIO8QEwhRnTC2LmxmBa5SE14= +github.com/goravel/file-rotatelogs/v2 v2.4.2 h1:g68AzbePXcm0V2CpUMc9j4qVzcDn7+7aoWSjZ51C0m4= +github.com/goravel/file-rotatelogs/v2 v2.4.2/go.mod h1:23VuSW8cBS4ax5cmbV+5AaiLpq25b8UJ96IhbAkdo8I= +github.com/goravel/framework v1.14.1 h1:VcJvzn1ItFQh/rQZO1EMkxKmzDrww1S+OGz4hjZi3UY= +github.com/goravel/framework v1.14.1/go.mod h1:rScDXGQZdoVfyxemNPmijlz/2a+lWNOa4jTuak5GGVg= +github.com/goravel/gin v1.2.1 h1:lnQX3NKUEaSx8x7AAJpoeVkXgi+MVQ9FXy4QywHQElo= +github.com/goravel/gin v1.2.1/go.mod h1:Qt3NJysg/eoxXL4y/swwFUcfcIT7XG+xb0rWChweZfY= +github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4= +github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM= +github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 h1:UH//fgunKIs4JdUbpDl1VZCDaL56wXCB/5+wF6uHfaI= +github.com/grpc-ecosystem/go-grpc-middleware v1.4.0/go.mod h1:g5qyo/la0ALbONm6Vbp88Yd8NsDy6rZz+RcrMPxvld8= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= +github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= +github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= +github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= +github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a h1:bbPeKD0xmW/Y25WS6cokEszi5g+S0QxI/d45PkRi7Nk= +github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= +github.com/jackc/pgx/v5 v5.5.4 h1:Xp2aQS8uXButQdnCMWNmvx6UysWQQC+u1EoizjguY+8= +github.com/jackc/pgx/v5 v5.5.4/go.mod h1:ez9gk+OAat140fv9ErkZDYFWmXLfV+++K0uAOiwgm1A= +github.com/jackc/puddle/v2 v2.2.1 h1:RhxXJtFG022u4ibrCSMSiu5aOq1i77R3OHKNJj77OAk= +github.com/jackc/puddle/v2 v2.2.1/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4= +github.com/jcmturner/aescts/v2 v2.0.0/go.mod h1:AiaICIRyfYg35RUkr8yESTqvSy7csK90qZ5xfvvsoNs= +github.com/jcmturner/dnsutils/v2 v2.0.0/go.mod h1:b0TnjGOvI/n42bZa+hmXL+kFJZsFT7G4t3HTlQ184QM= +github.com/jcmturner/gofork v1.7.6/go.mod h1:1622LH6i/EZqLloHfE7IeZ0uEJwMSUyQ/nDd82IeqRo= +github.com/jcmturner/goidentity/v6 v6.0.1/go.mod h1:X1YW3bgtvwAXju7V3LCIMpY0Gbxyjn/mY9zx4tFonSg= +github.com/jcmturner/gokrb5/v8 v8.4.4/go.mod h1:1btQEpgT6k+unzCwX1KdWMEwPPkkgBtP+F6aCACiMrs= +github.com/jcmturner/rpc/v2 v2.0.3/go.mod h1:VUJYCIDm3PVOEHw8sgt091/20OJjskO/YJki3ELg/Hc= +github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= +github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= +github.com/jinzhu/now v1.1.4/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= +github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ= +github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= +github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= +github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= +github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8= +github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= +github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg= +github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= +github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= +github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= +github.com/karrick/godirwalk v1.8.0/go.mod h1:H5KPZjojv4lE+QYImBI8xVtrBRgYrIVsaRPx4tDPEn4= +github.com/karrick/godirwalk v1.10.3/go.mod h1:RoGL9dQei4vP9ilrpETWE8CLOZ1kiN0LhBygSwrAsHA= +github.com/kelseyhightower/envconfig v1.4.0 h1:Im6hONhd3pLkfDFsbRgu68RDNkGF1r3dvMUtDTo2cv8= +github.com/kelseyhightower/envconfig v1.4.0/go.mod h1:cccZRl6mQpaq41TPp5QxidR+Sa3axMbJDNb//FQX6Gg= +github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/klauspost/compress v1.9.5/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= +github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= +github.com/klauspost/compress v1.17.7 h1:ehO88t2UGzQK66LMdE8tibEd1ErmzZjNEqWkjLAKQQg= +github.com/klauspost/compress v1.17.7/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= +github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= +github.com/klauspost/cpuid/v2 v2.0.10/go.mod h1:g2LTdtYhdyuGPqyWyv7qRAmj1WBqxuObKfj5c0PQa7c= +github.com/klauspost/cpuid/v2 v2.0.12/go.mod h1:g2LTdtYhdyuGPqyWyv7qRAmj1WBqxuObKfj5c0PQa7c= +github.com/klauspost/cpuid/v2 v2.2.8 h1:+StwCXwm9PdpiEkPyzBXIy+M9KUb4ODm0Zarf1kS5BM= +github.com/klauspost/cpuid/v2 v2.2.8/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= +github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= +github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= +github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ= +github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI= +github.com/lestrrat-go/envload v0.0.0-20180220234015-a3eb8ddeffcc h1:RKf14vYWi2ttpEmkA4aQ3j4u9dStX2t4M8UM6qqNsG8= +github.com/lestrrat-go/envload v0.0.0-20180220234015-a3eb8ddeffcc/go.mod h1:kopuH9ugFRkIXf3YoqHKyrJ9YfUFsckUU9S7B+XP+is= +github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= +github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= +github.com/lithammer/fuzzysearch v1.1.8 h1:/HIuJnjHuXS8bKaiTMeeDlW2/AyIWk2brx1V8LFgLN4= +github.com/lithammer/fuzzysearch v1.1.8/go.mod h1:IdqeyBClc3FFqSzYq/MXESsS4S0FsZ5ajtkr5xPLts4= +github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY= +github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= +github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= +github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= +github.com/markbates/oncer v0.0.0-20181203154359-bf2de49a0be2/go.mod h1:Ld9puTsIW75CHf65OeIOkyKbteujpZVXDpWK6YGZbxE= +github.com/markbates/safe v1.0.1/go.mod h1:nAqgmRi7cY2nqMc92/bSEeQA+R4OheNU2T1kNSCBdG0= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mattn/go-localereader v0.0.1 h1:ygSAOl7ZXTx4RdPYinUpg6W99U8jWvWi9Ye2JC/oIi4= +github.com/mattn/go-localereader v0.0.1/go.mod h1:8fBrzywKY7BI3czFoHkuzRoWE9C+EiG4R1k4Cjx5p88= +github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U= +github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +github.com/microsoft/go-mssqldb v1.6.0 h1:mM3gYdVwEPFrlg/Dvr2DNVEgYFG7L42l+dGc67NNNpc= +github.com/microsoft/go-mssqldb v1.6.0/go.mod h1:00mDtPbeQCRGC1HwOOR5K/gr30P1NcEG0vx6Kbv2aJU= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0= +github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/modocache/gover v0.0.0-20171022184752-b58185e213c5/go.mod h1:caMODM3PzxT8aQXRPkAt8xlV/e7d7w8GM5g0fa5F0D8= +github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc= +github.com/montanaflynn/stats v0.7.0/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow= +github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A= +github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= +github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 h1:ZK8zHtRHOkbHy6Mmr5D264iyp3TiX5OmNcI5cIARiQI= +github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6/go.mod h1:CJlz5H+gyd6CUWT45Oy4q24RdLyn7Md9Vj2/ldJBSIo= +github.com/muesli/cancelreader v0.2.2 h1:3I4Kt4BQjOR54NavqnDogx/MIoWBFa0StPA8ELUXHmA= +github.com/muesli/cancelreader v0.2.2/go.mod h1:3XuTXfFS2VjM+HTLZY9Ak0l6eUKfijIfMUZ4EgX0QYo= +github.com/muesli/termenv v0.15.2 h1:GohcuySI0QmI3wN8Ok9PtKGkgkFIk7y6Vpb5PvrY+Wo= +github.com/muesli/termenv v0.15.2/go.mod h1:Epx+iuz8sNs7mNKhxzH4fWXGNpZwUaJKRS1noLXviQ8= +github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= +github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= +github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= +github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= +github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= +github.com/onsi/gomega v1.16.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= +github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= +github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= +github.com/opencontainers/image-spec v1.0.2 h1:9yCKha/T5XdGtO0q9Q9a6T5NUCsTn/DrBg0D7ufOcFM= +github.com/opencontainers/image-spec v1.0.2/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= +github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= +github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs= +github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc= +github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc= +github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ= +github.com/pelletier/go-toml v1.7.0/go.mod h1:vwGMzjaWMwyfHwgIBhI2YUM4fB6nL6lVAvS1LBMMhTE= +github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM= +github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs= +github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 h1:KoWmjvw+nsYOo29YJK9vDA65RGE3NrOnUtO7a+RF9HU= +github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8/go.mod h1:HKlIX3XHQyzLZPlr7++PzdhaXEj94dEiJgZDTsxEqUI= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/pterm/pterm v0.12.27/go.mod h1:PhQ89w4i95rhgE+xedAoqous6K9X+r6aSOI2eFF7DZI= +github.com/pterm/pterm v0.12.29/go.mod h1:WI3qxgvoQFFGKGjGnJR849gU0TsEOvKn5Q8LlY1U7lg= +github.com/pterm/pterm v0.12.30/go.mod h1:MOqLIyMOgmTDz9yorcYbcw+HsgoZo3BQfg2wtl3HEFE= +github.com/pterm/pterm v0.12.31/go.mod h1:32ZAWZVXD7ZfG0s8qqHXePte42kdz8ECtRyEejaWgXU= +github.com/pterm/pterm v0.12.33/go.mod h1:x+h2uL+n7CP/rel9+bImHD5lF3nM9vJj80k9ybiiTTE= +github.com/pterm/pterm v0.12.36/go.mod h1:NjiL09hFhT/vWjQHSj1athJpx6H8cjpHXNAK5bUw8T8= +github.com/pterm/pterm v0.12.40/go.mod h1:ffwPLwlbXxP+rxT0GsgDTzS3y3rmpAO1NMjUkGTYf8s= +github.com/pterm/pterm v0.12.79 h1:lH3yrYMhdpeqX9y5Ep1u7DejyHy7NSQg9qrBjF9dFT4= +github.com/pterm/pterm v0.12.79/go.mod h1:1v/gzOF1N0FsjbgTHZ1wVycRkKiatFvJSJC4IGaQAAo= +github.com/rabbitmq/amqp091-go v1.9.0 h1:qrQtyzB4H8BQgEuJwhmVQqVHB9O4+MNDJCCAcpc3Aoo= +github.com/rabbitmq/amqp091-go v1.9.0/go.mod h1:+jPrT9iY2eLjRaMSRHUhc3z14E/l85kv/f+6luSD3pc= +github.com/redis/go-redis/v9 v9.0.2/go.mod h1:/xDTe9EF1LM61hek62Poq2nzQSGj0xSrEtEHbBQevps= +github.com/redis/go-redis/v9 v9.0.5/go.mod h1:WqMKv5vnQbRuZstUwxQI195wHy+t4PuXDOjzMvcuQHk= +github.com/redis/go-redis/v9 v9.5.3 h1:fOAp1/uJG+ZtcITgZOfYFmTKPE7n4Vclj1wZFgRciUU= +github.com/redis/go-redis/v9 v9.5.3/go.mod h1:hdY0cQFCN4fnSYT6TkisLufl/4W5UIXyv0b/CLO2V2M= +github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE= +github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= +github.com/rifflock/lfshook v0.0.0-20180920164130-b9218ef580f5 h1:mZHayPoR0lNmnHyvtYjDeq0zlVHn9K/ZXoy17ylucdo= +github.com/rifflock/lfshook v0.0.0-20180920164130-b9218ef580f5/go.mod h1:GEXHk5HgEKCvEIIrSpFI3ozzG5xOKA2DVlEX/gGnewM= +github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= +github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= +github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= +github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs= +github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro= +github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rogpeppe/go-internal v1.2.2/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= +github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA= +github.com/rotisserie/eris v0.5.4 h1:Il6IvLdAapsMhvuOahHWiBnl1G++Q0/L5UIkI5mARSk= +github.com/rotisserie/eris v0.5.4/go.mod h1:Z/kgYTJiJtocxCbFfvRmO+QejApzG6zpyky9G1A4g9s= +github.com/rs/cors v1.11.0 h1:0B9GE/r9Bc2UxRMMtymBkHTenPkHDv0CW4Y98GBY+po= +github.com/rs/cors v1.11.0/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= +github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= +github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/sagikazarmark/locafero v0.4.0 h1:HApY1R9zGo4DBgr7dqsTH/JJxLTTsOt7u6keLGt6kNQ= +github.com/sagikazarmark/locafero v0.4.0/go.mod h1:Pe1W6UlPYUk/+wc/6KFhbORCfqzgYEpgQ3O5fPuL3H4= +github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE= +github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ= +github.com/savioxavier/termlink v1.3.0 h1:3Gl4FzQjUyiHzmoEDfmWEhgIwDiJY4poOQHP+k8ReA4= +github.com/savioxavier/termlink v1.3.0/go.mod h1:5T5ePUlWbxCHIwyF8/Ez1qufOoGM89RCg9NvG+3G3gc= +github.com/sergi/go-diff v1.2.0 h1:XU+rvMAioB0UC3q1MFrIQy4Vo5/4VsRDQQXHsEya6xQ= +github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= +github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/sirupsen/logrus v1.4.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= +github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo= +github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0= +github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8= +github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY= +github.com/spf13/cast v1.6.0 h1:GEiTHELF+vaR5dhz3VqZfFSzZjYbgeKDpBxQVS4GYJ0= +github.com/spf13/cast v1.6.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= +github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= +github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/viper v1.19.0 h1:RWq5SEjt8o25SROyN3z2OrDB9l7RPd3lwTWU8EcEdcI= +github.com/spf13/viper v1.19.0/go.mod h1:GQUN9bilAbhU/jgc1bKs99f/suXKeUMct8Adx5+Ntkg= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= +github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/stvp/tempredis v0.0.0-20181119212430-b82af8480203 h1:QVqDTf3h2WHt08YuiTGPZLls0Wq99X9bWd0Q5ZSBesM= +github.com/stvp/tempredis v0.0.0-20181119212430-b82af8480203/go.mod h1:oqN97ltKNihBbwlX8dLpwxCl3+HnXKV/R0e+sRLd9C8= +github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= +github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= +github.com/tidwall/pretty v1.0.0 h1:HsD+QiTn7sK6flMKIvNmpqz1qrpP3Ps6jOKIKMooyg4= +github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= +github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= +github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= +github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE= +github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= +github.com/unrolled/secure v1.14.0 h1:u9vJTU/pR4Bny0ntLUMxdfLtmIRGvQf2sEFuA0TG9AE= +github.com/unrolled/secure v1.14.0/go.mod h1:BmF5hyM6tXczk3MpQkFf1hpKSRqCyhqcbiQtiAF7+40= +github.com/urfave/cli v1.22.5/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= +github.com/urfave/cli/v2 v2.27.2 h1:6e0H+AkS+zDckwPCUrZkKX38mRaau4nL2uipkJpbkcI= +github.com/urfave/cli/v2 v2.27.2/go.mod h1:g0+79LmHHATl7DAcHO99smiR/T7uGLw84w8Y42x+4eM= +github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c= +github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI= +github.com/xdg-go/scram v1.0.2/go.mod h1:1WAq6h33pAW+iRreB34OORO2Nf7qel3VV3fjBj+hCSs= +github.com/xdg-go/scram v1.1.1 h1:VOMT+81stJgXW3CpHyqHN3AXDYIMsx56mEFrB37Mb/E= +github.com/xdg-go/scram v1.1.1/go.mod h1:RaEWvsqvNKKvBPvcKeFjrG2cJqOkHTiyTpzz23ni57g= +github.com/xdg-go/stringprep v1.0.2/go.mod h1:8F9zXuvzgwmyT5DUm4GUfZGDdT3W+LCvS6+da4O5kxM= +github.com/xdg-go/stringprep v1.0.3 h1:kdwGpVNwPFtjs98xCGkHjQtGKh86rDcRZN17QEMCOIs= +github.com/xdg-go/stringprep v1.0.3/go.mod h1:W3f5j4i+9rC0kuIEJL0ky1VpHXQU3ocBgklLGvcBnW8= +github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c/go.mod h1:lB8K/P019DLNhemzwFU4jHLhdvlE6uDZjXFejJXr49I= +github.com/xdg/stringprep v0.0.0-20180714160509-73f8eece6fdc/go.mod h1:Jhud4/sHMO4oL310DaZAKk9ZaJ08SJfe+sJh0HrGL1Y= +github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778/go.mod h1:2MuV+tbUrU1zIOPMxZ5EncGwgmMJsa+9ucAQZXxsObs= +github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e h1:JVG44RsyaB9T2KIHavMF/ppJZNG9ZpyihvCd0w101no= +github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e/go.mod h1:RbqR21r5mrJuqunuUZ/Dhy/avygyECGrLceyNeo4LiM= +github.com/xrash/smetrics v0.0.0-20240312152122-5f08fbb34913 h1:+qGGcbkzsfDQNPPe9UDgpxAWQrhbbBXOYJFQDq/dtJw= +github.com/xrash/smetrics v0.0.0-20240312152122-5f08fbb34913/go.mod h1:4aEEwZQutDLsQv2Deui4iYQ6DWTxR14g6m8Wv88+Xqk= +github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d h1:splanxYIlg+5LfHAM6xpdFEAYOk8iySO56hMFq6uLyA= +github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA= +github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +go.einride.tech/aip v0.66.0 h1:XfV+NQX6L7EOYK11yoHHFtndeaWh3KbD9/cN/6iWEt8= +go.einride.tech/aip v0.66.0/go.mod h1:qAhMsfT7plxBX+Oy7Huol6YUvZ0ZzdUz26yZsQwfl1M= +go.mongodb.org/mongo-driver v1.4.6/go.mod h1:WcMNYLx/IlOxLe6JRJiv2uXuCz6zBLndR4SoGjYphSc= +go.mongodb.org/mongo-driver v1.7.5 h1:ny3p0reEpgsR2cfA5cjgwFZg3Cv/ofFh/8jbhGtz9VI= +go.mongodb.org/mongo-driver v1.7.5/go.mod h1:VXEWRZ6URJIkUq2SCAyapmhH0ZLRBP+FT4xhp5Zvxng= +go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= +go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= +go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= +go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= +go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0 h1:4Pp6oUg3+e/6M4C0A/3kJ2VYa++dsWVTtGgLVj5xtHg= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0/go.mod h1:Mjt1i1INqiaoZOMGR1RIUJN+i3ChKoFRqzrRQhlkbs0= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 h1:jq9TW8u3so/bN+JPT166wjOI6/vQPF6Xe7nMNIltagk= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0/go.mod h1:p8pYQP+m5XfbZm9fxtSKAbM6oIllS7s2AfxrChvc7iw= +go.opentelemetry.io/otel v1.24.0 h1:0LAOdjNmQeSTzGBzduGe/rU4tZhMwL5rWgtp9Ku5Jfo= +go.opentelemetry.io/otel v1.24.0/go.mod h1:W7b9Ozg4nkF5tWI5zsXkaKKDjdVjpD4oAt9Qi/MArHo= +go.opentelemetry.io/otel/metric v1.24.0 h1:6EhoGWWK28x1fbpA4tYTOWBkPefTDQnb8WSGXlc88kI= +go.opentelemetry.io/otel/metric v1.24.0/go.mod h1:VYhLe1rFfxuTXLgj4CBiyz+9WYBA8pNGJgDcSFRKBco= +go.opentelemetry.io/otel/sdk v1.22.0 h1:6coWHw9xw7EfClIC/+O31R8IY3/+EiRFHevmHafB2Gw= +go.opentelemetry.io/otel/sdk v1.22.0/go.mod h1:iu7luyVGYovrRpe2fmj3CVKouQNdTOkxtLzPvPz1DOc= +go.opentelemetry.io/otel/trace v1.24.0 h1:CsKnnL4dUAr/0llH9FKuc698G04IrpWV0MQA/Y1YELI= +go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU= +go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE= +go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= +go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= +go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A= +go.uber.org/goleak v1.2.1/go.mod h1:qlT2yGI9QafXHhZZLxlSuNsMw3FFLxBr+tBRlmO1xH4= +go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= +go.uber.org/multierr v1.9.0 h1:7fIwc/ZtS0q++VgcfqFDxSBZVv/Xo49/SYnDFupUwlI= +go.uber.org/multierr v1.9.0/go.mod h1:X2jQV1h+kxSjClGpnseKVIxpmcjrj7MNnI0bnlfKTVQ= +go.uber.org/zap v1.18.1/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI= +golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= +golang.org/x/arch v0.8.0 h1:3wRIsP3pM4yUptoR96otTUOXI367OS0+c9eeRi9doIc= +golang.org/x/arch v0.8.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190422162423-af44ce270edf/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= +golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190530122614-20be4c3c3ed5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= +golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= +golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0= +golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw= +golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= +golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg= +golang.org/x/crypto v0.24.0 h1:mnl8DM0o513X8fdIkmyFE/5hTYxbwYOjDS/+rK6qpRI= +golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= +golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= +golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= +golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= +golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= +golang.org/x/exp v0.0.0-20230905200255-921286631fa9 h1:GoHiUyI/Tp2nVkLI2mCxVkOjsbSXD66ic0XW0js0R9g= +golang.org/x/exp v0.0.0-20230905200255-921286631fa9/go.mod h1:S2oDrQGGwySpoQPVqRShND87VCbxmc6bL1Yd2oYrm6k= +golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= +golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= +golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= +golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= +golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= +golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= +golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA= +golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= +golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI= +golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= +golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY= +golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac= +golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210113205817-d3ed898aa8a3/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.18.0 h1:09qnuIAgzdx1XplqJvW6CQqMCtGZykZWcXzPMPUusvI= +golang.org/x/oauth2 v0.18.0/go.mod h1:Wf7knwG0MPoWIMMBgFlEaSUDaKskp0dCfrlJRJXbBi8= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190412183630-56d357773e84/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= +golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= +golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190419153524-e8e3143a4f4a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190531175056-4c3a928424d2/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191010194322-b09406accb47/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210616045830-e2b7044e8c71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211013075003-97ac67df715c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws= +golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= +golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= +golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU= +golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU= +golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY= +golang.org/x/term v0.21.0 h1:WVXCp+/EBEHOj53Rvu+7KiT/iElMrO8ACK16SMZ3jaA= +golang.org/x/term v0.21.0/go.mod h1:ooXLefLobQVslOqselCNF4SxFAaoS6KujMbsGzSDmX0= +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4= +golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= +golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20201208040808-7e3f01d25324/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= +golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190329151228-23e29df326fe/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190416151739-9c9e1878f421/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190420181800-aa740d480789/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190531172133-b3315ee88b7d/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= +golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= +golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= +golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= +golang.org/x/tools v0.17.0/go.mod h1:xsh6VxdV005rRVaS6SSAf9oiAqljS7UZUacMZ8Bnsps= +golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg= +golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= +google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= +google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= +google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= +google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= +google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE= +google.golang.org/api v0.39.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= +google.golang.org/api v0.171.0 h1:w174hnBPqut76FzW5Qaupt7zY8Kql6fiVjgys4f58sU= +google.golang.org/api v0.171.0/go.mod h1:Hnq5AHm4OTMt2BUVjael2CWZFD6vksJdWCWiUAmjC9o= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= +google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM= +google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= +google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= +google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200423170343-7949de9c1215/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= +google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210207032614-bba0dbe2a9ea/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de h1:F6qOa9AZTYJXOUEr4jDysRDLrm4PHePlge4v4TGAlxY= +google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de/go.mod h1:VUhTRKeHn9wwcdrk73nvdC9gF178Tzhmt/qyaFcPLSo= +google.golang.org/genproto/googleapis/api v0.0.0-20240318140521-94a12d6c2237 h1:RFiFrvy37/mpSpdySBDrUdipW/dHwsRwh3J3+A9VgT4= +google.golang.org/genproto/googleapis/api v0.0.0-20240318140521-94a12d6c2237/go.mod h1:Z5Iiy3jtmioajWHDGFk7CeugTyHtPvMHA4UTmUkyalE= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237 h1:NnYq6UN9ReLM9/Y01KWNOWyI5xQ9kbIms5GGJVwS/Yc= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237/go.mod h1:WtryC6hu0hhx87FDGxWCDptyssuo68sk10vYjF+T9fY= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= +google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= +google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= +google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= +google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= +google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= +google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.64.0 h1:KH3VH9y/MgNQg1dE7b3XfVK0GsPSIzJwdF617gUSbvY= +google.golang.org/grpc v1.64.0/go.mod h1:oxjF8E3FBnjp+/gVFYdWacaLDx9na1aqy9oovLpxQYg= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= +google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg= +google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= +gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gorm.io/driver/mysql v1.4.3/go.mod h1:sSIebwZAVPiT+27jK9HIwvsqOGKx3YMPmrA3mBJR10c= +gorm.io/driver/mysql v1.5.6 h1:Ld4mkIickM+EliaQZQx3uOJDJHtrd70MxAUqWqlx3Y8= +gorm.io/driver/mysql v1.5.6/go.mod h1:sEtPWMiqiN1N1cMXoXmBbd8C6/l+TESwriotuRRpkDM= +gorm.io/driver/postgres v1.5.7 h1:8ptbNJTDbEmhdr62uReG5BGkdQyeasu/FZHxI0IMGnM= +gorm.io/driver/postgres v1.5.7/go.mod h1:3e019WlBaYI5o5LIdNV+LyxCMNtLOQETBXL2h4chKpA= +gorm.io/driver/sqlserver v1.5.3 h1:rjupPS4PVw+rjJkfvr8jn2lJ8BMhT4UW5FwuJY0P3Z0= +gorm.io/driver/sqlserver v1.5.3/go.mod h1:B+CZ0/7oFJ6tAlefsKoyxdgDCXJKSgwS2bMOQZT0I00= +gorm.io/gorm v1.23.8/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk= +gorm.io/gorm v1.25.2/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k= +gorm.io/gorm v1.25.7-0.20240204074919-46816ad31dde/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8= +gorm.io/gorm v1.25.7/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8= +gorm.io/gorm v1.25.10 h1:dQpO+33KalOA+aFYGlK+EfxcI5MbO7EP2yYygwh9h+s= +gorm.io/gorm v1.25.10/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8= +gorm.io/plugin/dbresolver v1.5.1 h1:s9Dj9f7r+1rE3nx/Ywzc85nXptUEaeOO0pt27xdopM8= +gorm.io/plugin/dbresolver v1.5.1/go.mod h1:l4Cn87EHLEYuqUncpEeTC2tTJQkjngPSD+lo8hIvcT0= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +modernc.org/libc v1.37.6 h1:orZH3c5wmhIQFTXF+Nt+eeauyd+ZIt2BX6ARe+kD+aw= +modernc.org/libc v1.37.6/go.mod h1:YAXkAZ8ktnkCKaN9sw/UDeUVkGYJ/YquGO4FTi5nmHE= +modernc.org/mathutil v1.6.0 h1:fRe9+AmYlaej+64JsEEhoWuAYBkOtQiMEU7n/XgfYi4= +modernc.org/mathutil v1.6.0/go.mod h1:Ui5Q9q1TR2gFm0AQRqQUaBWFLAhQpCwNcuhBOSedWPo= +modernc.org/memory v1.7.2 h1:Klh90S215mmH8c9gO98QxQFsY+W451E8AnzjoE2ee1E= +modernc.org/memory v1.7.2/go.mod h1:NO4NVCQy0N7ln+T9ngWqOQfi7ley4vpwvARR+Hjw95E= +modernc.org/sqlite v1.28.0 h1:Zx+LyDDmXczNnEQdvPuEfcFVA2ZPyaD7UCZDjef3BHQ= +modernc.org/sqlite v1.28.0/go.mod h1:Qxpazz0zH8Z1xCFyi5GSL3FzbtZ3fvbjmywNogldEW0= +nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50= +rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= +rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= +rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= +rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= diff --git a/frameworks/Go/goravel/src/gin/main.go b/frameworks/Go/goravel/src/gin/main.go new file mode 100644 index 00000000000..ddd89a4e1a1 --- /dev/null +++ b/frameworks/Go/goravel/src/gin/main.go @@ -0,0 +1,27 @@ +package main + +import ( + "github.com/goravel/framework/facades" + "github.com/goravel/framework/foundation" + + "goravel/config" +) + +func main() { + app := foundation.NewApplication() + + // Bootstrap the application + app.Boot() + + // Bootstrap the config. + config.Boot() + + // Start HTTP server by facades.Route(). + go func() { + if err := facades.Route().Run(); err != nil { + facades.Log().Errorf("Route run error: %v", err) + } + }() + + select {} +} diff --git a/frameworks/Go/goravel/src/gin/resources/views/fortunes.tmpl b/frameworks/Go/goravel/src/gin/resources/views/fortunes.tmpl new file mode 100644 index 00000000000..4c58fa53da0 --- /dev/null +++ b/frameworks/Go/goravel/src/gin/resources/views/fortunes.tmpl @@ -0,0 +1,22 @@ +{{define "fortunes.tmpl"}} + + + + Fortunes + + + + + + + + {{range .fortunes}} + + + + + {{end}} +
idmessage
{{.ID}}{{.Message}}
+ + +{{end}} diff --git a/frameworks/Go/goravel/src/gin/routes/web.go b/frameworks/Go/goravel/src/gin/routes/web.go new file mode 100644 index 00000000000..86bfbccc2d4 --- /dev/null +++ b/frameworks/Go/goravel/src/gin/routes/web.go @@ -0,0 +1,19 @@ +package routes + +import ( + "github.com/goravel/framework/facades" + + "goravel/app/http/controllers" +) + +func Web() { + testController := controllers.NewTestController() + facades.Route().Get("/plaintext", testController.Plaintext) + facades.Route().Get("/json", testController.JSON) + facades.Route().Get("/db", testController.DB) + facades.Route().Get("/queries", testController.Queries) + facades.Route().Get("/update", testController.Update) + facades.Route().Get("/fortunes", testController.Fortunes) + facades.Route().Get("/cached-worlds", testController.CacheQueries) + +} From c225d2aac662fc647e7a2b85c59c44b0ce52aff5 Mon Sep 17 00:00:00 2001 From: pavelmash <7467039+pavelmash@users.noreply.github.com> Date: Mon, 1 Jul 2024 20:50:03 +0300 Subject: [PATCH 003/204] [mORMot] fixed GPF on plaintext endpoint 2.2.7693 (#9121) Co-authored-by: pavel.mash --- frameworks/Pascal/mormot/setup_and_build.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frameworks/Pascal/mormot/setup_and_build.sh b/frameworks/Pascal/mormot/setup_and_build.sh index 85863798754..ed0c26034e8 100755 --- a/frameworks/Pascal/mormot/setup_and_build.sh +++ b/frameworks/Pascal/mormot/setup_and_build.sh @@ -35,7 +35,7 @@ echo "Download statics from $URL ..." wget -qO- "$URL" | tar -xz -C ./libs/mORMot/static # uncomment for fixed commit URL -URL=https://github.com/synopse/mORMot2/tarball/f0fc66c954cd45f5c581e52c21170923805a683b +URL=https://github.com/synopse/mORMot2/tarball/a0dda41833c3d32531080d1eeb5a1627540d62e9 #URL="https://api.github.com/repos/synopse/mORMot2/tarball/$USED_TAG" echo "Download and unpacking mORMot sources from $URL ..." wget -qO- "$URL" | tar -xz -C ./libs/mORMot --strip-components=1 From 3c91fd5b639be1383bdeef90ed69005a72b87d2a Mon Sep 17 00:00:00 2001 From: Henry Date: Tue, 2 Jul 2024 01:50:14 +0800 Subject: [PATCH 004/204] beetlex update RawDb (#9117) * update beetleX to BeetleX.Light * update beetlex to beetlex.light * fix fortunes error * fix error * remove beetlex-core-updb * update * update benchmark_config * update * update * update * update RawDb * update * update * update * update * update dbraw --- .../beetlex/PlatformBenchmarks/DBRaw.cs | 425 ++++++++---------- .../beetlex/PlatformBenchmarks/GMTDate.cs | 14 +- .../PlatformBenchmarks/HttpHandler.Caching.cs | 2 +- .../beetlex/PlatformBenchmarks/HttpHandler.cs | 22 +- .../PlatformBenchmarks/HttpHandler.db.cs | 4 +- .../HttpHandler.fortunes.cs | 24 +- .../PlatformBenchmarks/HttpHandler.json.cs | 10 +- .../HttpHandler.plaintext.cs | 23 +- .../PlatformBenchmarks/HttpHandler.queries.cs | 2 +- .../PlatformBenchmarks/HttpHandler.updates.cs | 2 +- .../beetlex/PlatformBenchmarks/HttpServer.cs | 28 +- .../PlatformBenchmarks.csproj | 2 +- .../beetlex/PlatformBenchmarks/Program.cs | 1 - 13 files changed, 243 insertions(+), 316 deletions(-) diff --git a/frameworks/CSharp/beetlex/PlatformBenchmarks/DBRaw.cs b/frameworks/CSharp/beetlex/PlatformBenchmarks/DBRaw.cs index ca668243fe7..6aae831fcbb 100644 --- a/frameworks/CSharp/beetlex/PlatformBenchmarks/DBRaw.cs +++ b/frameworks/CSharp/beetlex/PlatformBenchmarks/DBRaw.cs @@ -10,110 +10,44 @@ using Microsoft.Extensions.Caching.Memory; using Npgsql; +using System.Runtime.CompilerServices; namespace PlatformBenchmarks { - public class RawDb + public sealed class RawDb { - private readonly ConcurrentRandom _random; + private readonly MemoryCache _cache + = new(new MemoryCacheOptions { ExpirationScanFrequency = TimeSpan.FromMinutes(60) }); - private readonly DbProviderFactory _dbProviderFactory; - - private readonly static MemoryCache _cache = new MemoryCache( - new MemoryCacheOptions() - { - ExpirationScanFrequency = TimeSpan.FromMinutes(60) - }); - - private static readonly object[] _cacheKeys = Enumerable.Range(0, 10001).Select((i) => new CacheKey(i)).ToArray(); + private static DbProviderFactory _dbProviderFactory => Npgsql.NpgsqlFactory.Instance; + private readonly string _connectionString; - public static string _connectionString = null; - - public RawDb(ConcurrentRandom random, DbProviderFactory dbProviderFactory) + public RawDb(ConcurrentRandom random, string connectionString) { _random = random; - _dbProviderFactory = dbProviderFactory; - OnCreateCommand(); - } - private void OnCreateCommand() - { - SingleCommand = new Npgsql.NpgsqlCommand(); - SingleCommand.CommandText = "SELECT id, randomnumber FROM world WHERE id = @Id"; - mID = new Npgsql.NpgsqlParameter("@Id", _random.Next(1, 10001)); - SingleCommand.Parameters.Add(mID); - FortuneCommand = new Npgsql.NpgsqlCommand(); - FortuneCommand.CommandText = "SELECT id, message FROM fortune"; - } - - private DbCommand SingleCommand; - - private DbCommand FortuneCommand; - - private Npgsql.NpgsqlParameter mID; - - private static int ListDefaultSize = 8; - - private World[] mWorldBuffer = null; - - private World[] GetWorldBuffer() - { - if (mWorldBuffer == null) - mWorldBuffer = new World[512]; - return mWorldBuffer; - } - - private Fortune[] mFortunesBuffer = null; - - private Fortune[] GetFortuneBuffer() - { - if (mFortunesBuffer == null) - mFortunesBuffer = new Fortune[512]; - return mFortunesBuffer; + _connectionString = connectionString; } public async Task LoadSingleQueryRow() { - using (var db = _dbProviderFactory.CreateConnection()) - { - db.ConnectionString = _connectionString; - await db.OpenAsync(); - SingleCommand.Connection = db; - mID.TypedValue = _random.Next(1, 10001); - return await ReadSingleRow(db, SingleCommand); - - } - } - - async Task ReadSingleRow(DbConnection connection, DbCommand cmd) - { - using (var rdr = await cmd.ExecuteReaderAsync(CommandBehavior.SingleRow)) - + using (var connection = (NpgsqlConnection)_dbProviderFactory.CreateConnection()) { - await rdr.ReadAsync(); - return new World + connection.ConnectionString = _connectionString; + await connection.OpenAsync(); + var (cmd, _) = CreateReadCommand(connection); + using (var command = cmd) { - Id = rdr.GetInt32(0), - RandomNumber = rdr.GetInt32(1) - }; - } - } - public async Task> LoadMultipleQueriesRows(int count) - { - using (var db = _dbProviderFactory.CreateConnection()) - { - db.ConnectionString = _connectionString; - await db.OpenAsync(); - return await LoadMultipleRows(count, db); + return await ReadSingleRow(cmd); + } } } - - public Task LoadCachedQueries(int count) + public Task LoadCachedQueries(int count) { - var result = new World[count]; + var result = new CachedWorld[count]; var cacheKeys = _cacheKeys; var cache = _cache; var random = _random; @@ -121,42 +55,40 @@ public Task LoadCachedQueries(int count) { var id = random.Next(1, 10001); var key = cacheKeys[id]; - var data = cache.Get(key); - - if (data != null) + if (cache.TryGetValue(key, out var cached)) { - result[i] = data; + result[i] = (CachedWorld)cached; } else { - return LoadUncachedQueries(id, i, count, this, result); + return LoadUncachedQueries(_connectionString, id, i, count, this, result); } } return Task.FromResult(result); - static async Task LoadUncachedQueries(int id, int i, int count, RawDb rawdb, World[] result) + static async Task LoadUncachedQueries(string conn, int id, int i, int count, RawDb rawdb, CachedWorld[] result) { - using (var db = new NpgsqlConnection(_connectionString)) + using (var connection = (NpgsqlConnection)_dbProviderFactory.CreateConnection()) { - await db.OpenAsync(); - Func> create = async (entry) => - { - return await rawdb.ReadSingleRow(db, rawdb.SingleCommand); - }; + connection.ConnectionString = conn; + await connection.OpenAsync(); + var (cmd, idParameter) = rawdb.CreateReadCommand(connection); + using var command = cmd; + async Task create(ICacheEntry _) => await ReadSingleRow(cmd); + var cacheKeys = _cacheKeys; var key = cacheKeys[id]; - rawdb.SingleCommand.Connection = db; - rawdb.mID.TypedValue = id; + idParameter.TypedValue = id; + for (; i < result.Length; i++) { - var data = await _cache.GetOrCreateAsync(key, create); - result[i] = data; + result[i] = await rawdb._cache.GetOrCreateAsync(key, create); + id = rawdb._random.Next(1, 10001); - rawdb.SingleCommand.Connection = db; - rawdb.mID.TypedValue = id; + idParameter.TypedValue = id; key = cacheKeys[id]; } } @@ -164,215 +96,212 @@ static async Task LoadUncachedQueries(int id, int i, int count, RawDb r } } - - private async Task> LoadMultipleRows(int count, DbConnection db) + public async Task PopulateCache() { - SingleCommand.Connection = db; - SingleCommand.Parameters[0].Value = _random.Next(1, 10001); - var result = GetWorldBuffer(); - for (int i = 0; i < count; i++) + using (var connection = (NpgsqlConnection)_dbProviderFactory.CreateConnection()) { - result[i] = await ReadSingleRow(db, SingleCommand); - SingleCommand.Parameters[0].Value = _random.Next(1, 10001); + connection.ConnectionString = _connectionString; + await connection.OpenAsync(); + var (cmd, idParameter) = CreateReadCommand(connection); + using var command = cmd; + + var cacheKeys = _cacheKeys; + var cache = _cache; + for (var i = 1; i < 10001; i++) + { + idParameter.TypedValue = i; + cache.Set(cacheKeys[i], await ReadSingleRow(cmd)); + } } - return new ArraySegment(result, 0, count); + Console.WriteLine("Caching Populated"); } - public async Task> LoadFortunesRows() + public async Task LoadMultipleQueriesRows(int count) { - int count = 0; - var result = GetFortuneBuffer(); - using (var db = new NpgsqlConnection(_connectionString)) + var results = new World[count]; + + using (var connection = (NpgsqlConnection)_dbProviderFactory.CreateConnection()) { - await db.OpenAsync(); - FortuneCommand.Connection = db; - using (var rdr = await FortuneCommand.ExecuteReaderAsync()) + connection.ConnectionString = _connectionString; + await connection.OpenAsync(); + + using var batch = new NpgsqlBatch(connection) + { + // Inserts a PG Sync message between each statement in the batch, required for compliance with + // TechEmpower general test requirement 7 + // https://github.com/TechEmpower/FrameworkBenchmarks/wiki/Project-Information-Framework-Tests-Overview + EnableErrorBarriers = true + }; + + for (var i = 0; i < count; i++) { - while (await rdr.ReadAsync()) + batch.BatchCommands.Add(new() { - result[count] = (new Fortune - { - Id = rdr.GetInt32(0), - Message = rdr.GetString(1) - }); - count++; - } + CommandText = "SELECT id, randomnumber FROM world WHERE id = $1", + Parameters = { new NpgsqlParameter { TypedValue = _random.Next(1, 10001) } } + }); + } + + using var reader = await batch.ExecuteReaderAsync(); + + for (var i = 0; i < count; i++) + { + await reader.ReadAsync(); + results[i] = new World { Id = reader.GetInt32(0), RandomNumber = reader.GetInt32(1) }; + await reader.NextResultAsync(); } } - result[count] = (new Fortune { Message = "Additional fortune added at request time." }); - count++; - Array.Sort(result, 0, count); - return new ArraySegment(result, 0, count); + return results; } + public async Task LoadMultipleUpdatesRows(int count) { - using (var db = new NpgsqlConnection(_connectionString)) + var results = new World[count]; + + using (var connection = (NpgsqlConnection)_dbProviderFactory.CreateConnection()) { - await db.OpenAsync(); - var updateCmd = UpdateCommandsCached.PopCommand(count); - try + connection.ConnectionString = _connectionString; + await connection.OpenAsync(); + var (queryCmd, queryParameter) = CreateReadCommand(connection); + using (queryCmd) { - var command = updateCmd.Command; - command.Connection = db; - SingleCommand.Connection = db; - mID.TypedValue = _random.Next(1, int.MaxValue) % 10000 + 1; - var results = new World[count]; - for (int i = 0; i < count; i++) + for (var i = 0; i < results.Length; i++) { - results[i] = await ReadSingleRow(db, SingleCommand); - mID.TypedValue = _random.Next(1, int.MaxValue) % 10000 + 1; + results[i] = await ReadSingleRow(queryCmd); + queryParameter.TypedValue = _random.Next(1, 10001); } + } - for (int i = 0; i < count; i++) + using (var updateCmd = new NpgsqlCommand(BatchUpdateString.Query(count), connection)) + { + for (var i = 0; i < results.Length; i++) { - var randomNumber = _random.Next(1, int.MaxValue) % 10000 + 1; - updateCmd.Parameters[i * 2].TypedValue = results[i].Id; - updateCmd.Parameters[i * 2 + 1].TypedValue = randomNumber; - //updateCmd.Parameters[i * 2].Value = results[i].Id; - //updateCmd.Parameters[i * 2 + 1].Value = randomNumber; + var randomNumber = _random.Next(1, 10001); + + updateCmd.Parameters.Add(new NpgsqlParameter { TypedValue = results[i].Id }); + updateCmd.Parameters.Add(new NpgsqlParameter { TypedValue = randomNumber }); + results[i].RandomNumber = randomNumber; } - await command.ExecuteNonQueryAsync(); - return results; - } - catch (Exception e_) - { - throw e_; - } - finally - { - UpdateCommandsCached.PushCommand(count, updateCmd); + await updateCmd.ExecuteNonQueryAsync(); } } - } - } + return results; + } - public sealed class CacheKey : IEquatable - { - private readonly int _value; + public async Task> LoadFortunesRows() + { + // Benchmark requirements explicitly prohibit pre-initializing the list size + var result = new List(); - public CacheKey(int value) - => _value = value; + using (var connection = (NpgsqlConnection)_dbProviderFactory.CreateConnection()) + { + connection.ConnectionString = _connectionString; + await connection.OpenAsync(); - public bool Equals(CacheKey key) - => key._value == _value; + using (var cmd = new NpgsqlCommand("SELECT id, message FROM fortune", connection)) + { - public override bool Equals(object obj) - => ReferenceEquals(obj, this); + using (var rdr = await cmd.ExecuteReaderAsync()) + { - public override int GetHashCode() - => _value; + while (await rdr.ReadAsync()) + { + result.Add(new Fortune + { + Id = rdr.GetInt32(0), + Message = rdr.GetString(1) + }); + } + } + } + } + result.Add(new Fortune { Message = "Additional fortune added at request time." }); + result.Sort(); - public override string ToString() - => _value.ToString(); - } + return result; + } - internal class UpdateCommandsCached - { - private static System.Collections.Concurrent.ConcurrentStack[] mCacheTable - = new System.Collections.Concurrent.ConcurrentStack[1024]; - public static string[] IDParamereNames = new string[1024]; + private (NpgsqlCommand readCmd, NpgsqlParameter idParameter) CreateReadCommand(NpgsqlConnection connection) + { + var cmd = new NpgsqlCommand("SELECT id, randomnumber FROM world WHERE id = $1", connection); + var parameter = new NpgsqlParameter { TypedValue = _random.Next(1, 10001) }; - public static string[] RandomParamereNames = new string[1024]; + cmd.Parameters.Add(parameter); - static UpdateCommandsCached() - { - for (int i = 0; i < 1024; i++) - { - IDParamereNames[i] = $"@Id_{i}"; - RandomParamereNames[i] = $"@Random_{i}"; - mCacheTable[i] = new System.Collections.Concurrent.ConcurrentStack(); - } + return (cmd, parameter); } - private static CommandCacheItem CreatCommand(int count) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static async Task ReadSingleRow(NpgsqlCommand cmd) { - CommandCacheItem item = new CommandCacheItem(); - NpgsqlCommand cmd = new Npgsql.NpgsqlCommand(); - cmd.CommandText = BatchUpdateString.Query(count); - for (int i = 0; i < count; i++) - { - var id = new NpgsqlParameter(); - id.ParameterName = IDParamereNames[i]; - cmd.Parameters.Add(id); - item.Parameters.Add(id); - - var random = new NpgsqlParameter(); - random.ParameterName = RandomParamereNames[i]; - cmd.Parameters.Add(random); - item.Parameters.Add(random); - } - item.Command = cmd; - return item; + using var rdr = await cmd.ExecuteReaderAsync(System.Data.CommandBehavior.SingleRow); + await rdr.ReadAsync(); + return new World + { + Id = rdr.GetInt32(0), + RandomNumber = rdr.GetInt32(1) + }; } - public static void PushCommand(int count, CommandCacheItem cmd) - { - mCacheTable[count].Push(cmd); - } + private static readonly object[] _cacheKeys = Enumerable.Range(0, 10001).Select((i) => new CacheKey(i)).ToArray(); - public static CommandCacheItem PopCommand(int count) + public sealed class CacheKey : IEquatable { - if (mCacheTable[count].TryPop(out CommandCacheItem cmd)) - return cmd; - return CreatCommand(count); - } + private readonly int _value; - private static bool mInited = false; + public CacheKey(int value) + => _value = value; - public static void Init() - { - if (mInited) - return; - lock (typeof(UpdateCommandsCached)) - { - if (mInited) - return; - for (int i = 1; i <= 500; i++) - { - for (int k = 0; k < 10; k++) - { - var cmd = CreatCommand(i); - mCacheTable[i].Push(cmd); - } - } - mInited = true; - return; - } - } - } + public bool Equals(CacheKey key) + => key._value == _value; - class CommandCacheItem - { - public Npgsql.NpgsqlCommand Command { get; set; } + public override bool Equals(object obj) + => ReferenceEquals(obj, this); - public List> Parameters { get; private set; } = new List>(1024); + public override int GetHashCode() + => _value; + + public override string ToString() + => _value.ToString(); + } } - internal class BatchUpdateString + internal sealed class BatchUpdateString { private const int MaxBatch = 500; + internal static readonly string[] ParamNames = Enumerable.Range(0, MaxBatch * 2).Select(i => $"@p{i}").ToArray(); + private static string[] _queries = new string[MaxBatch + 1]; public static string Query(int batchSize) + => _queries[batchSize] is null + ? CreateBatch(batchSize) + : _queries[batchSize]; + + private static string CreateBatch(int batchSize) { - if (_queries[batchSize] != null) + var sb = StringBuilderCache.Acquire(); + + + sb.Append("UPDATE world SET randomNumber = temp.randomNumber FROM (VALUES "); + var c = 1; + for (var i = 0; i < batchSize; i++) { - return _queries[batchSize]; + if (i > 0) + sb.Append(", "); + sb.Append($"(${c++}, ${c++})"); } + sb.Append(" ORDER BY 1) AS temp(id, randomNumber) WHERE temp.id = world.id"); + - var lastIndex = batchSize - 1; - var sb = StringBuilderCache.Acquire(); - sb.Append("UPDATE world SET randomNumber = temp.randomNumber FROM (VALUES "); - Enumerable.Range(0, lastIndex).ToList().ForEach(i => sb.Append($"(@Id_{i}, @Random_{i}), ")); - sb.Append($"(@Id_{lastIndex}, @Random_{lastIndex}) ORDER BY 1) AS temp(id, randomNumber) WHERE temp.id = world.id"); return _queries[batchSize] = StringBuilderCache.GetStringAndRelease(sb); } } diff --git a/frameworks/CSharp/beetlex/PlatformBenchmarks/GMTDate.cs b/frameworks/CSharp/beetlex/PlatformBenchmarks/GMTDate.cs index 76e15ce9f7f..bfd6b79223a 100644 --- a/frameworks/CSharp/beetlex/PlatformBenchmarks/GMTDate.cs +++ b/frameworks/CSharp/beetlex/PlatformBenchmarks/GMTDate.cs @@ -49,7 +49,7 @@ public static GMTDate Default } } - public ArraySegment DATE + public Memory DATE { get; set; @@ -95,18 +95,20 @@ private void Init() }, null, 1000, 1000); } - private ArraySegment GetData() + private Memory GetData() { return GetData(DateTime.Now); } + + public void Write(IStreamWriter stream) { - var data = DATE; - stream.Write(data.Array, 0, data.Count); + + stream.Write(DATE.Span); } - private ArraySegment GetData(DateTime date) + private Memory GetData(DateTime date) { date = date.ToUniversalTime(); int offset13 = 0; @@ -190,7 +192,7 @@ private ArraySegment GetData(DateTime date) buffer[offset13] = _n; offset13++; - return new ArraySegment(GTM_BUFFER, 0, offset13); + return new Memory(GTM_BUFFER, 0, offset13); } } diff --git a/frameworks/CSharp/beetlex/PlatformBenchmarks/HttpHandler.Caching.cs b/frameworks/CSharp/beetlex/PlatformBenchmarks/HttpHandler.Caching.cs index 2b2264ea60a..2794fcbdd82 100644 --- a/frameworks/CSharp/beetlex/PlatformBenchmarks/HttpHandler.Caching.cs +++ b/frameworks/CSharp/beetlex/PlatformBenchmarks/HttpHandler.Caching.cs @@ -33,7 +33,7 @@ public async Task caching(string queryString, IStreamWriter stream) ContentLengthMemory content = new ContentLengthMemory(); try { - var data = await _db.LoadCachedQueries(count); + var data = await DB.LoadCachedQueries(count); stream.Write(_jsonResultPreamble.Data, 0, _jsonResultPreamble.Length); content.Data = GetContentLengthMemory(stream); GMTDate.Default.Write(stream); diff --git a/frameworks/CSharp/beetlex/PlatformBenchmarks/HttpHandler.cs b/frameworks/CSharp/beetlex/PlatformBenchmarks/HttpHandler.cs index e623afdd72b..117d19fee9a 100644 --- a/frameworks/CSharp/beetlex/PlatformBenchmarks/HttpHandler.cs +++ b/frameworks/CSharp/beetlex/PlatformBenchmarks/HttpHandler.cs @@ -47,7 +47,6 @@ public partial class HttpHandler : SesionBase private static readonly AsciiString _path_Fortunes = "/fortunes"; - private static readonly AsciiString _result_plaintext = "Hello, World!"; private static readonly AsciiString _cached_worlds = "/cached-worlds"; @@ -55,19 +54,6 @@ public partial class HttpHandler : SesionBase - private readonly static AsciiString _jsonPreamble = - _httpsuccess - + _headerContentTypeJson - + _headerServer - + _headerContentLength + _jsonPayloadSize.ToString() + _line; - - private readonly static AsciiString _plaintextPreamble = - _httpsuccess - + _headerContentTypeText - + _headerServer - + _headerContentLength + _result_plaintext.Length.ToString() + _line; - - private readonly static AsciiString _jsonResultPreamble = _httpsuccess + _headerContentTypeJson @@ -122,14 +108,14 @@ public HttpHandler() private Queue _Requests = new Queue(); - private RawDb _db; + public static RawDb DB; private RequestData _ReadRequest = null; public override void Connected(NetContext context) { base.Connected(context); this.Context = context; - _db = new RawDb(new ConcurrentRandom(), Npgsql.NpgsqlFactory.Instance); ; + } private int AnalysisUrl(ReadOnlySpan url) @@ -255,11 +241,11 @@ private void AnalysisAction(ReadOnlySequence line, out ActionType type, ou Span baseUrl = stackalloc byte[baseurlLen]; url.Slice(0, baseurlLen).CopyTo(baseUrl); - if (baseUrl.Length == _path_Plaintext.Length && baseUrl.StartsWith(_path_Plaintext)) + if (baseUrl.Length == _path_Plaintext.Length && baseUrl[1] == 'p') { type = ActionType.Plaintext; } - else if (baseUrl.Length == _path_Json.Length && baseUrl.StartsWith(_path_Json)) + else if (baseUrl.Length == _path_Json.Length && baseUrl[1] == 'j') { type = ActionType.Json; } diff --git a/frameworks/CSharp/beetlex/PlatformBenchmarks/HttpHandler.db.cs b/frameworks/CSharp/beetlex/PlatformBenchmarks/HttpHandler.db.cs index 27c71d43f13..1604195625e 100644 --- a/frameworks/CSharp/beetlex/PlatformBenchmarks/HttpHandler.db.cs +++ b/frameworks/CSharp/beetlex/PlatformBenchmarks/HttpHandler.db.cs @@ -17,8 +17,8 @@ public async Task db(IStreamWriter stream) try { - var data = await _db.LoadSingleQueryRow(); - stream.Write(_jsonResultPreamble.Data, 0, _jsonResultPreamble.Length); + var data = await DB.LoadSingleQueryRow(); + stream.Write(_jsonResultPreamble.AsSpan()); content.Data = GetContentLengthMemory(stream); GMTDate.Default.Write(stream); stream.WriteSequenceNetStream.StartWriteLength(); diff --git a/frameworks/CSharp/beetlex/PlatformBenchmarks/HttpHandler.fortunes.cs b/frameworks/CSharp/beetlex/PlatformBenchmarks/HttpHandler.fortunes.cs index 829c18bd68a..7bb2fc40acb 100644 --- a/frameworks/CSharp/beetlex/PlatformBenchmarks/HttpHandler.fortunes.cs +++ b/frameworks/CSharp/beetlex/PlatformBenchmarks/HttpHandler.fortunes.cs @@ -21,11 +21,11 @@ static HtmlEncoder CreateHtmlEncoder() return HtmlEncoder.Create(settings); } - private readonly static AsciiString _fortunesTableStart = "Fortunes"; - private readonly static AsciiString _fortunesRowStart = ""; - private readonly static AsciiString _fortunesTableEnd = "
idmessage
"; - private readonly static AsciiString _fortunesColumn = ""; - private readonly static AsciiString _fortunesRowEnd = "
"; + private static ReadOnlySpan _fortunesTableStart => "Fortunes"u8; + private static ReadOnlySpan _fortunesRowStart => ""u8; + private static ReadOnlySpan _fortunesTableEnd => "
idmessage
"u8; + private static ReadOnlySpan _fortunesColumn => ""u8; + private static ReadOnlySpan _fortunesRowEnd => "
"u8; public async Task fortunes(IStreamWriter stream) @@ -34,23 +34,23 @@ public async Task fortunes(IStreamWriter stream) try { - var data = await this._db.LoadFortunesRows(); + var data = await DB.LoadFortunesRows(); - stream.Write(_HtmlResultPreamble.Data, 0, _HtmlResultPreamble.Length); + stream.Write(_HtmlResultPreamble); content.Data = GetContentLengthMemory(stream); GMTDate.Default.Write(stream); stream.WriteSequenceNetStream.StartWriteLength(); - stream.Write(_fortunesTableStart.Data, 0, _fortunesTableStart.Length); + stream.Write(_fortunesTableStart); foreach (var item in data) { - stream.Write(_fortunesRowStart.Data, 0, _fortunesRowStart.Length); + stream.Write(_fortunesRowStart); stream.WriteString(item.Id.ToString(CultureInfo.InvariantCulture)); - stream.Write(_fortunesColumn.Data, 0, _fortunesColumn.Length); + stream.Write(_fortunesColumn); stream.WriteString(htmlEncoder.Encode(item.Message)); - stream.Write(_fortunesRowEnd.Data, 0, _fortunesRowEnd.Length); + stream.Write(_fortunesRowEnd); } - stream.Write(_fortunesTableEnd.Data, 0, _fortunesTableEnd.Length); + stream.Write(_fortunesTableEnd); } catch (Exception e_) { diff --git a/frameworks/CSharp/beetlex/PlatformBenchmarks/HttpHandler.json.cs b/frameworks/CSharp/beetlex/PlatformBenchmarks/HttpHandler.json.cs index 1bfa2d8863f..4a379e98931 100644 --- a/frameworks/CSharp/beetlex/PlatformBenchmarks/HttpHandler.json.cs +++ b/frameworks/CSharp/beetlex/PlatformBenchmarks/HttpHandler.json.cs @@ -14,10 +14,14 @@ namespace PlatformBenchmarks public partial class HttpHandler { - + private static ReadOnlySpan _jsonPreamble => + "HTTP/1.1 200 OK\r\n"u8 + + "Server: B\r\n"u8 + + "Content-Type: application/json\r\n"u8 + + "Content-Length: 27\r\n"u8; public void Json(IStreamWriter stream) { - stream.Write(_jsonPreamble.Data, 0, _jsonPreamble.Length); + stream.Write(_jsonPreamble); GMTDate.Default.Write(stream); var jsonWriter = GetJsonWriter(stream); using (var unflush = stream.UnFlush()) @@ -27,7 +31,7 @@ public void Json(IStreamWriter stream) jsonWriter.WriteEndObject(); jsonWriter.Flush(); } - + } } } diff --git a/frameworks/CSharp/beetlex/PlatformBenchmarks/HttpHandler.plaintext.cs b/frameworks/CSharp/beetlex/PlatformBenchmarks/HttpHandler.plaintext.cs index a011d52f7f4..fe50d21011d 100644 --- a/frameworks/CSharp/beetlex/PlatformBenchmarks/HttpHandler.plaintext.cs +++ b/frameworks/CSharp/beetlex/PlatformBenchmarks/HttpHandler.plaintext.cs @@ -2,6 +2,7 @@ using BeetleX.Light.Memory; using System; using System.Collections.Generic; +using System.Data; using System.Text; using System.Threading.Tasks; @@ -9,13 +10,27 @@ namespace PlatformBenchmarks { public partial class HttpHandler { - + private static ReadOnlySpan _plaintextPreamble => + "HTTP/1.1 200 OK\r\n"u8 + + "Server: B\r\n"u8 + + "Content-Type: text/plain\r\n"u8 + + "Content-Length: 13\r\n"u8; + + private static ReadOnlySpan _plainTextBody => "Hello, World!"u8; public void Plaintext(IStreamWriter stream) { - stream.Write(_plaintextPreamble.Data, 0, _plaintextPreamble.Length); - GMTDate.Default.Write(stream); - stream.Write(_result_plaintext.Data, 0, _result_plaintext.Length); + Span data = stream.WriteSequenceNetStream.GetWriteSpan(256); + var timedata = GMTDate.Default.DATE; + _plaintextPreamble.CopyTo(data); + data = data.Slice(_plaintextPreamble.Length); + timedata.Span.CopyTo(data); + data = data.Slice(timedata.Length); + _plainTextBody.CopyTo(data); + //stream.Write(_plaintextPreamble.AsSpan()); + //GMTDate.Default.Write(stream); + //stream.Write(_result_plaintext.Data.AsSpan()); + stream.WriteSequenceNetStream.WriteAdvance(_plaintextPreamble.Length + timedata.Length + _plainTextBody.Length); } } } diff --git a/frameworks/CSharp/beetlex/PlatformBenchmarks/HttpHandler.queries.cs b/frameworks/CSharp/beetlex/PlatformBenchmarks/HttpHandler.queries.cs index 53eef8a31fb..4e7039176dd 100644 --- a/frameworks/CSharp/beetlex/PlatformBenchmarks/HttpHandler.queries.cs +++ b/frameworks/CSharp/beetlex/PlatformBenchmarks/HttpHandler.queries.cs @@ -31,7 +31,7 @@ public async ValueTask queries(string queryString, IStreamWriter stream) ContentLengthMemory content = new ContentLengthMemory(); try { - var data = await _db.LoadMultipleQueriesRows(count); + var data = await DB.LoadMultipleQueriesRows(count); stream.Write(_jsonResultPreamble.Data, 0, _jsonResultPreamble.Length); content.Data = GetContentLengthMemory(stream); GMTDate.Default.Write(stream); diff --git a/frameworks/CSharp/beetlex/PlatformBenchmarks/HttpHandler.updates.cs b/frameworks/CSharp/beetlex/PlatformBenchmarks/HttpHandler.updates.cs index 255a430c070..99d938f32a5 100644 --- a/frameworks/CSharp/beetlex/PlatformBenchmarks/HttpHandler.updates.cs +++ b/frameworks/CSharp/beetlex/PlatformBenchmarks/HttpHandler.updates.cs @@ -32,7 +32,7 @@ public async ValueTask updates(string queryString, IStreamWriter stream) ContentLengthMemory content = new ContentLengthMemory(); try { - var data = await _db.LoadMultipleUpdatesRows(count); + var data = await DB.LoadMultipleUpdatesRows(count); stream.Write(_jsonResultPreamble.Data, 0, _jsonResultPreamble.Length); content.Data = GetContentLengthMemory(stream); diff --git a/frameworks/CSharp/beetlex/PlatformBenchmarks/HttpServer.cs b/frameworks/CSharp/beetlex/PlatformBenchmarks/HttpServer.cs index b8ee7c5f495..b6cb8e3a1a0 100644 --- a/frameworks/CSharp/beetlex/PlatformBenchmarks/HttpServer.cs +++ b/frameworks/CSharp/beetlex/PlatformBenchmarks/HttpServer.cs @@ -13,13 +13,19 @@ public class HttpServer : IHostedService { private static NetServer _apiServer; - public virtual Task StartAsync(CancellationToken cancellationToken) + public static string _connectionString; + + public virtual async Task StartAsync(CancellationToken cancellationToken) { + _connectionString = "Server=tfb-database;Database=hello_world;User Id=benchmarkdbuser;Password=benchmarkdbpass;SSL Mode=Disable;Maximum Pool Size=16;NoResetOnClose=true;Enlist=false;Max Auto Prepare=4;Multiplexing=true;Write Coalescing Buffer Threshold Bytes=1000"; + //_connectionString = "Server=localhost;Database=hello_world;User Id=benchmarkdbuser;Password=benchmarkdbpass;SSL Mode=Disable;Maximum Pool Size=16;NoResetOnClose=true;Enlist=false;Max Auto Prepare=4;Multiplexing=true;Write Coalescing Buffer Threshold Bytes=1000"; ThreadPool.SetMinThreads(Environment.ProcessorCount * 2, Environment.ProcessorCount * 2); - Constants.MemorySegmentMinSize = 1024 * 8; - Constants.MemorySegmentMaxSize = 1024 * 8; + Constants.MemorySegmentMinSize = 1024 * 16; + Constants.MemorySegmentMaxSize = 1024 * 16; Constants.InitMemoryBlock(); - ArraySegment date = GMTDate.Default.DATE; + var date = GMTDate.Default.DATE; + HttpHandler.DB = new RawDb(new ConcurrentRandom(), HttpServer._connectionString); + await HttpHandler.DB.PopulateCache(); _apiServer = new NetServer(); _apiServer.Options.LogLevel = BeetleX.Light.Logs.LogLevel.Error; _apiServer.Options.AddLogOutputHandler(); @@ -30,20 +36,6 @@ public virtual Task StartAsync(CancellationToken cancellationToken) _apiServer.Start(); - if (!Program.UpDB) - { - RawDb._connectionString = "Server=tfb-database;Database=hello_world;User Id=benchmarkdbuser;Password=benchmarkdbpass;SSL Mode=Disable;Maximum Pool Size=64;NoResetOnClose=true;Enlist=false;Max Auto Prepare=4;Multiplexing=true;Write Coalescing Buffer Threshold Bytes=1000"; - //RawDb._connectionString = "Server=127.0.0.1;Database=hello_world;User Id=benchmarkdbuser;Password=benchmarkdbpass;Maximum Pool Size=256;NoResetOnClose=true;Enlist=false;Max Auto Prepare=3"; - } - else - { - - RawDb._connectionString = "Server=tfb-database;Database=hello_world;User Id=benchmarkdbuser;Password=benchmarkdbpass;SSL Mode=Disable;Maximum Pool Size=64;NoResetOnClose=true;Enlist=false;Max Auto Prepare=4;Multiplexing=true;Write Coalescing Buffer Threshold Bytes=1000"; - //RawDb._connectionString = "Server=127.0.0.1;Database=hello_world;User Id=benchmarkdbuser;Password=benchmarkdbpass;Maximum Pool Size=64;NoResetOnClose=true;Enlist=false;Max Auto Prepare=3"; - } - // ApiServer.Log(LogType.Info, null, $"Debug mode [{Program.Debug}]"); - return Task.CompletedTask; - } public virtual Task StopAsync(CancellationToken cancellationToken) diff --git a/frameworks/CSharp/beetlex/PlatformBenchmarks/PlatformBenchmarks.csproj b/frameworks/CSharp/beetlex/PlatformBenchmarks/PlatformBenchmarks.csproj index 10202a882be..ba5b9d4202d 100644 --- a/frameworks/CSharp/beetlex/PlatformBenchmarks/PlatformBenchmarks.csproj +++ b/frameworks/CSharp/beetlex/PlatformBenchmarks/PlatformBenchmarks.csproj @@ -8,7 +8,7 @@ - + diff --git a/frameworks/CSharp/beetlex/PlatformBenchmarks/Program.cs b/frameworks/CSharp/beetlex/PlatformBenchmarks/Program.cs index 3819a6c7e1d..ab262ef92a3 100644 --- a/frameworks/CSharp/beetlex/PlatformBenchmarks/Program.cs +++ b/frameworks/CSharp/beetlex/PlatformBenchmarks/Program.cs @@ -17,7 +17,6 @@ public static void Main(string[] args) //Debug = (args != null && args.Length > 0 && args[0] == "debug"); var data = GMTDate.Default.DATE; UpDB = (args != null && args.Length > 0 && args[0] == "updb"); - UpdateCommandsCached.Init(); //HttpServer server = new HttpServer(); //server.StartAsync(default); //Console.ReadLine(); From e33a7759a48caeab2eb51ca8338fe42dcadb4ac6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 1 Jul 2024 17:50:34 +0000 Subject: [PATCH 005/204] Bump io.undertow:undertow-core in /frameworks/Java/undertow Bumps [io.undertow:undertow-core](https://github.com/undertow-io/undertow) from 2.3.12.Final to 2.3.14.Final. - [Release notes](https://github.com/undertow-io/undertow/releases) - [Commits](https://github.com/undertow-io/undertow/compare/2.3.12.Final...2.3.14.Final) --- updated-dependencies: - dependency-name: io.undertow:undertow-core dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- frameworks/Java/undertow/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frameworks/Java/undertow/pom.xml b/frameworks/Java/undertow/pom.xml index 1a0f95afd69..da2a6dd086b 100644 --- a/frameworks/Java/undertow/pom.xml +++ b/frameworks/Java/undertow/pom.xml @@ -20,7 +20,7 @@ 3.2.2 0.9.10 42.7.2 - 2.3.12.Final + 2.3.14.Final From eedd5e5c8acb8a1f8110ddc49576a53a513ce63d Mon Sep 17 00:00:00 2001 From: James Burns Date: Mon, 8 Jul 2024 11:23:27 -0400 Subject: [PATCH 006/204] [Go/echo] Update to pgx (#9134) --- frameworks/Go/echo/echo.dockerfile | 2 +- frameworks/Go/echo/src/go.mod | 8 +++-- frameworks/Go/echo/src/go.sum | 17 +++++++--- frameworks/Go/echo/src/main.go | 51 ++++++++++++++---------------- 4 files changed, 43 insertions(+), 35 deletions(-) diff --git a/frameworks/Go/echo/echo.dockerfile b/frameworks/Go/echo/echo.dockerfile index ccc8c0186d2..ab6a616d4d9 100644 --- a/frameworks/Go/echo/echo.dockerfile +++ b/frameworks/Go/echo/echo.dockerfile @@ -1,4 +1,4 @@ -FROM docker.io/golang:1.19 +FROM docker.io/golang:1.22 ADD ./src /echo WORKDIR /echo diff --git a/frameworks/Go/echo/src/go.mod b/frameworks/Go/echo/src/go.mod index 63fe7fd1cef..04c940547d5 100644 --- a/frameworks/Go/echo/src/go.mod +++ b/frameworks/Go/echo/src/go.mod @@ -1,13 +1,16 @@ module echo/app -go 1.19 +go 1.22 require ( + github.com/jackc/pgx/v5 v5.6.0 github.com/labstack/echo/v4 v4.9.0 - github.com/lib/pq v1.10.7 ) require ( + github.com/jackc/pgpassfile v1.0.0 // indirect + github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect + github.com/jackc/puddle/v2 v2.2.1 // indirect github.com/labstack/gommon v0.3.1 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.16 // indirect @@ -15,6 +18,7 @@ require ( github.com/valyala/fasttemplate v1.2.1 // indirect golang.org/x/crypto v0.21.0 // indirect golang.org/x/net v0.23.0 // indirect + golang.org/x/sync v0.1.0 // indirect golang.org/x/sys v0.18.0 // indirect golang.org/x/text v0.14.0 // indirect ) diff --git a/frameworks/Go/echo/src/go.sum b/frameworks/Go/echo/src/go.sum index 8732c64400d..e607732cf1b 100644 --- a/frameworks/Go/echo/src/go.sum +++ b/frameworks/Go/echo/src/go.sum @@ -1,12 +1,18 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= +github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= +github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a h1:bbPeKD0xmW/Y25WS6cokEszi5g+S0QxI/d45PkRi7Nk= +github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= +github.com/jackc/pgx/v5 v5.6.0 h1:SWJzexBzPL5jb0GEsrPMLIsi/3jOo7RHlzTjcAeDrPY= +github.com/jackc/pgx/v5 v5.6.0/go.mod h1:DNZ/vlrUnhWCoFGxHAG8U2ljioxukquj7utPDgtQdTw= +github.com/jackc/puddle/v2 v2.2.1 h1:RhxXJtFG022u4ibrCSMSiu5aOq1i77R3OHKNJj77OAk= +github.com/jackc/puddle/v2 v2.2.1/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4= github.com/labstack/echo/v4 v4.9.0 h1:wPOF1CE6gvt/kmbMR4dGzWvHMPT+sAEUJOwOTtvITVY= github.com/labstack/echo/v4 v4.9.0/go.mod h1:xkCDAdFCIf8jsFQ5NnbK7oqaF/yU1A1X20Ltm0OvSks= github.com/labstack/gommon v0.3.1 h1:OomWaJXm7xR6L1HmEtGyQf26TEn7V6X88mktX9kee9o= github.com/labstack/gommon v0.3.1/go.mod h1:uW6kP17uPlLJsD3ijUYn3/M5bAxtlZhMI6m3MFxTMTM= -github.com/lib/pq v1.10.7 h1:p7ZhMD+KsSRozJr34udlUrhboJwWAgCg34+/ZZNvZZw= -github.com/lib/pq v1.10.7/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/mattn/go-colorable v0.1.11/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= @@ -16,8 +22,9 @@ github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= github.com/valyala/fasttemplate v1.2.1 h1:TVEnxayobAdVkhQfrfes2IzOB6o+z4roRkPF52WA1u4= @@ -26,6 +33,8 @@ golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA= golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs= golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= +golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= +golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211103235746-7861aae1554b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -36,5 +45,5 @@ golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= diff --git a/frameworks/Go/echo/src/main.go b/frameworks/Go/echo/src/main.go index ed999f215c0..4642ee2f5b1 100644 --- a/frameworks/Go/echo/src/main.go +++ b/frameworks/Go/echo/src/main.go @@ -1,9 +1,11 @@ package main import ( - "database/sql" + "context" "encoding/json" "fmt" + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgxpool" "html/template" "io" "log" @@ -13,7 +15,6 @@ import ( "strconv" "github.com/labstack/echo/v4" - _ "github.com/lib/pq" ) type ( @@ -79,10 +80,7 @@ const ( var ( // Database - db *sql.DB - worldSelectStmt *sql.Stmt - worldUpdateStmt *sql.Stmt - fortuneSelectStmt *sql.Stmt + db *pgxpool.Pool // Template Template = &StdTemplate{ @@ -120,8 +118,9 @@ func (h *handler) json() echo.HandlerFunc { // Test 2: Single database query func (h *handler) db() echo.HandlerFunc { return func(c echo.Context) error { + ctx := c.Request().Context() world := new(World) - if err := fetchRandomWorld(world); err != nil { + if err := fetchRandomWorld(ctx, world); err != nil { return err } @@ -134,10 +133,11 @@ func (h *handler) db() echo.HandlerFunc { // Test 3: Multiple database queries func (h *handler) queries() echo.HandlerFunc { return func(c echo.Context) error { + ctx := c.Request().Context() n := getQueryCount(c.QueryParam("n")) worlds := make([]World, n) for i := 0; i < n; i++ { - if err := fetchRandomWorld(&worlds[i]); err != nil { + if err := fetchRandomWorld(ctx, &worlds[i]); err != nil { return err } } @@ -151,7 +151,8 @@ func (h *handler) queries() echo.HandlerFunc { // Test 4: Fortunes func (h *handler) fortunes() echo.HandlerFunc { return func(c echo.Context) error { - rows, err := fortuneSelectStmt.Query() + ctx := c.Request().Context() + rows, err := db.Query(ctx, fortuneSelect) if err != nil { return fmt.Errorf("Error preparing statement: %v", err) } @@ -172,18 +173,19 @@ func (h *handler) fortunes() echo.HandlerFunc { // Test 5: Database updates func (h *handler) updates() echo.HandlerFunc { return func(c echo.Context) error { + ctx := c.Request().Context() n := getQueryCount(c.QueryParam("n")) worlds := make([]World, n) for i := 0; i < n; i++ { // Fetch and modify w := &worlds[i] - if err := fetchRandomWorld(&worlds[i]); err != nil { + if err := fetchRandomWorld(ctx, &worlds[i]); err != nil { return err } w.RandomNumber = uint16(randomWorldNum()) // Update - if _, err := worldUpdateStmt.Exec(w.RandomNumber, w.ID); err != nil { + if _, err := db.Exec(ctx, worldUpdate, w.RandomNumber, w.ID); err != nil { return fmt.Errorf("Error updating world row: %v", err) } } @@ -221,9 +223,9 @@ func (h *handler) plaintext() echo.HandlerFunc { } } -func fetchRandomWorld(w *World) error { +func fetchRandomWorld(ctx context.Context, w *World) error { n := randomWorldNum() - return worldSelectStmt.QueryRow(n).Scan(&w.ID, &w.RandomNumber) + return db.QueryRow(ctx, worldSelect, n).Scan(&w.ID, &w.RandomNumber) } func randomWorldNum() int { @@ -241,7 +243,7 @@ func getQueryCount(q string) int { return n } -func fetchFortunes(rows *sql.Rows) (Fortunes, error) { +func fetchFortunes(rows pgx.Rows) (Fortunes, error) { fortunes := make(Fortunes, 0) for rows.Next() { // Fetch rows f := new(Fortune) @@ -267,24 +269,17 @@ func InitPostgres() { host := "tfb-database" var err error - db, err = sql.Open("postgres", fmt.Sprintf(connectionString, host)) - if err != nil { - log.Fatalf("Error opening database: %v", err) - } - db.SetMaxIdleConns(maxConnections) - db.SetMaxOpenConns(maxConnections) - worldSelectStmt, err = db.Prepare(worldSelect) + dbCfg, err := pgxpool.ParseConfig(fmt.Sprintf(connectionString, host)) if err != nil { - log.Fatal(err) + log.Fatalf("Error reading database connection string: %v", err) } - worldUpdateStmt, err = db.Prepare(worldUpdate) - if err != nil { - log.Fatal(err) - } - fortuneSelectStmt, err = db.Prepare(fortuneSelect) + dbCfg.MaxConns = maxConnections + dbCfg.MinConns = maxConnections + + db, err = pgxpool.NewWithConfig(context.Background(), dbCfg) if err != nil { - log.Fatal(err) + log.Fatalf("Error opening database: %v", err) } } From b0c5935e9b518af59d1e02f3110555f9d3770a40 Mon Sep 17 00:00:00 2001 From: Xudong Huang Date: Mon, 8 Jul 2024 23:23:39 +0800 Subject: [PATCH 007/204] [Rust|may-minihttp] update may_postgres (#9150) --- frameworks/Rust/may-minihttp/Cargo.toml | 2 +- frameworks/Rust/may-minihttp/may-minihttp.dockerfile | 2 +- frameworks/Rust/may-minihttp/src/main.rs | 5 +++-- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/frameworks/Rust/may-minihttp/Cargo.toml b/frameworks/Rust/may-minihttp/Cargo.toml index 019aaf898a2..9fc7760ff8e 100644 --- a/frameworks/Rust/may-minihttp/Cargo.toml +++ b/frameworks/Rust/may-minihttp/Cargo.toml @@ -19,7 +19,7 @@ buf-min = { version = "0.7", features = ["bytes"] } may = { version = "0.3", default-features = false } may_minihttp = { version = "0.1", default-features = false } -may_postgres = { git = "https://github.com/Xudong-Huang/may_postgres.git", rev = "5ea3fb9", default-features = false } +may_postgres = { git = "https://github.com/Xudong-Huang/may_postgres.git", rev = "917ed78", default-features = false } [profile.release] opt-level = 3 diff --git a/frameworks/Rust/may-minihttp/may-minihttp.dockerfile b/frameworks/Rust/may-minihttp/may-minihttp.dockerfile index 0ddda28e3eb..160e563ac2c 100644 --- a/frameworks/Rust/may-minihttp/may-minihttp.dockerfile +++ b/frameworks/Rust/may-minihttp/may-minihttp.dockerfile @@ -1,4 +1,4 @@ -FROM rust:1.78 +FROM rust:1.79 RUN apt-get update -yqq && apt-get install -yqq cmake g++ diff --git a/frameworks/Rust/may-minihttp/src/main.rs b/frameworks/Rust/may-minihttp/src/main.rs index f6a817031c3..33b410b1c0f 100644 --- a/frameworks/Rust/may-minihttp/src/main.rs +++ b/frameworks/Rust/may-minihttp/src/main.rs @@ -49,7 +49,7 @@ struct PgConnectionPool { impl PgConnectionPool { fn new(db_url: &'static str, size: usize) -> PgConnectionPool { let clients = (0..size) - .map(|_| std::thread::spawn(move || PgConnection::new(db_url))) + .map(|_| may::go!(move || PgConnection::new(db_url))) .collect::>(); let mut clients: Vec<_> = clients.into_iter().map(|t| t.join().unwrap()).collect(); clients.sort_by(|a, b| (a.client.id() % size).cmp(&(b.client.id() % size))); @@ -59,6 +59,7 @@ impl PgConnectionPool { fn get_connection(&self, id: usize) -> PgConnection { let len = self.clients.len(); let connection = &self.clients[id % len]; + // assert_eq!(connection.client.id() % len, id % len); PgConnection { client: connection.client.clone(), statement: connection.statement.clone(), @@ -282,7 +283,7 @@ impl HttpServiceFactory for HttpServer { fn main() { may::config().set_pool_capacity(1000).set_stack_size(0x1000); - println!("Starting http server: 127.0.0.1:8080"); + println!("Starting http server: 0.0.0.1:8080"); let server = HttpServer { db_pool: PgConnectionPool::new( "postgres://benchmarkdbuser:benchmarkdbpass@tfb-database/hello_world", From 0940648a225b7f988034e980731b23fbf6d652da Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 8 Jul 2024 08:25:09 -0700 Subject: [PATCH 008/204] Bump mysql2 from 3.9.7 to 3.9.8 in /frameworks/JavaScript/spliffy (#9138) Bumps [mysql2](https://github.com/sidorares/node-mysql2) from 3.9.7 to 3.9.8. - [Release notes](https://github.com/sidorares/node-mysql2/releases) - [Changelog](https://github.com/sidorares/node-mysql2/blob/master/Changelog.md) - [Commits](https://github.com/sidorares/node-mysql2/compare/v3.9.7...v3.9.8) --- updated-dependencies: - dependency-name: mysql2 dependency-type: direct:production ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- frameworks/JavaScript/spliffy/package-lock.json | 6 +++--- frameworks/JavaScript/spliffy/package.json | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/frameworks/JavaScript/spliffy/package-lock.json b/frameworks/JavaScript/spliffy/package-lock.json index db22f966f30..40b146ce31c 100644 --- a/frameworks/JavaScript/spliffy/package-lock.json +++ b/frameworks/JavaScript/spliffy/package-lock.json @@ -1189,9 +1189,9 @@ } }, "mysql2": { - "version": "3.9.7", - "resolved": "https://registry.npmjs.org/mysql2/-/mysql2-3.9.7.tgz", - "integrity": "sha512-KnJT8vYRcNAZv73uf9zpXqNbvBG7DJrs+1nACsjZP1HMJ1TgXEy8wnNilXAn/5i57JizXKtrUtwDB7HxT9DDpw==", + "version": "3.9.8", + "resolved": "https://registry.npmjs.org/mysql2/-/mysql2-3.9.8.tgz", + "integrity": "sha512-+5JKNjPuks1FNMoy9TYpl77f+5frbTklz7eb3XDwbpsERRLEeXiW2PDEkakYF50UuKU2qwfGnyXpKYvukv8mGA==", "requires": { "denque": "^2.1.0", "generate-function": "^2.3.1", diff --git a/frameworks/JavaScript/spliffy/package.json b/frameworks/JavaScript/spliffy/package.json index bdb6b49aa45..62b2240acf3 100644 --- a/frameworks/JavaScript/spliffy/package.json +++ b/frameworks/JavaScript/spliffy/package.json @@ -6,7 +6,7 @@ "@srfnstack/spliffy": "0.6.1", "html-escaper": "3.0.3", "mongodb": "^4.17.0", - "mysql2": "^3.9.7", + "mysql2": "^3.9.8", "node-cache": "5.1.2", "pg": "8.6.0", "pg-native": "3.0.1" From 172e539de92f0d7d27a16c32466ae064d6710ad8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 8 Jul 2024 08:25:32 -0700 Subject: [PATCH 009/204] Bump github.com/gofiber/fiber/v2 in /frameworks/Go/fiber/src (#9139) Bumps [github.com/gofiber/fiber/v2](https://github.com/gofiber/fiber) from 2.52.1 to 2.52.5. - [Release notes](https://github.com/gofiber/fiber/releases) - [Commits](https://github.com/gofiber/fiber/compare/v2.52.1...v2.52.5) --- updated-dependencies: - dependency-name: github.com/gofiber/fiber/v2 dependency-type: direct:production ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- frameworks/Go/fiber/src/go.mod | 2 +- frameworks/Go/fiber/src/go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/frameworks/Go/fiber/src/go.mod b/frameworks/Go/fiber/src/go.mod index 2372b8f57f7..bb9b8bc5701 100644 --- a/frameworks/Go/fiber/src/go.mod +++ b/frameworks/Go/fiber/src/go.mod @@ -4,7 +4,7 @@ go 1.19 require ( github.com/goccy/go-json v0.10.0 - github.com/gofiber/fiber/v2 v2.52.1 + github.com/gofiber/fiber/v2 v2.52.5 github.com/jackc/pgx/v5 v5.5.4 github.com/valyala/quicktemplate v1.7.0 ) diff --git a/frameworks/Go/fiber/src/go.sum b/frameworks/Go/fiber/src/go.sum index 5ae0d5e53e3..1414375d002 100644 --- a/frameworks/Go/fiber/src/go.sum +++ b/frameworks/Go/fiber/src/go.sum @@ -6,8 +6,8 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/goccy/go-json v0.10.0 h1:mXKd9Qw4NuzShiRlOXKews24ufknHO7gx30lsDyokKA= github.com/goccy/go-json v0.10.0/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= -github.com/gofiber/fiber/v2 v2.52.1 h1:1RoU2NS+b98o1L77sdl5mboGPiW+0Ypsi5oLmcYlgHI= -github.com/gofiber/fiber/v2 v2.52.1/go.mod h1:KEOE+cXMhXG0zHc9d8+E38hoX+ZN7bhOtgeF2oT6jrQ= +github.com/gofiber/fiber/v2 v2.52.5 h1:tWoP1MJQjGEe4GB5TUGOi7P2E0ZMMRx5ZTG4rT+yGMo= +github.com/gofiber/fiber/v2 v2.52.5/go.mod h1:KEOE+cXMhXG0zHc9d8+E38hoX+ZN7bhOtgeF2oT6jrQ= github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/uuid v1.5.0 h1:1p67kYwdtXjb0gL0BPiP1Av9wiZPo5A8z2cWkTZ+eyU= github.com/google/uuid v1.5.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= From 6cb7e7b24f54d4b71c7fc0647be1aa00fd0512d6 Mon Sep 17 00:00:00 2001 From: Petrik de Heus Date: Mon, 8 Jul 2024 17:25:49 +0200 Subject: [PATCH 010/204] [rails] Use Ruby 3.4-rc (#9087) --- frameworks/Ruby/rails/rails-mysql.dockerfile | 2 +- frameworks/Ruby/rails/rails.dockerfile | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/frameworks/Ruby/rails/rails-mysql.dockerfile b/frameworks/Ruby/rails/rails-mysql.dockerfile index 370b08ba493..a93f26b52da 100644 --- a/frameworks/Ruby/rails/rails-mysql.dockerfile +++ b/frameworks/Ruby/rails/rails-mysql.dockerfile @@ -1,4 +1,4 @@ -FROM ruby:3.3 +FROM ruby:3.4-rc RUN apt-get update -yqq && apt-get install -yqq --no-install-recommends redis-server diff --git a/frameworks/Ruby/rails/rails.dockerfile b/frameworks/Ruby/rails/rails.dockerfile index 3e02770b190..9d75f7d359e 100644 --- a/frameworks/Ruby/rails/rails.dockerfile +++ b/frameworks/Ruby/rails/rails.dockerfile @@ -1,4 +1,4 @@ -FROM ruby:3.3 +FROM ruby:3.4-rc RUN apt-get update -yqq && apt-get install -yqq --no-install-recommends redis-server From bba72a8b146ad9d772159872f9676818eda12cc7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Kon=C3=B4pka?= Date: Mon, 8 Jul 2024 17:26:18 +0200 Subject: [PATCH 011/204] Update spring tests to current release of spring-boot (#8876) * Update spring-boot to 3.2.4 * Disable open-in-view globally for all tests open-in-view is unfortunately enabled by default for historical reasons, see https://github.com/spring-projects/spring-boot/issues/7107 This significantly improves performance for requests where db connection is not needed at all, i.e. json & plaintext db ~3% improvement json ~17% improvement query ~no change update ~no change fortune ~5% improvement plaintext ~29% improvement * Make spring-webflux tests work again Replaces old milestone version of spring boot with current release 3.2.5 Also replaces ParalllelGC with default one, i.e. G1GC * Update spring-boot to v3.3.0 * Update to java 21 * Enable virtual threads * Fix excessive number of queries in JPA tests ... query and follow up update statement must be enclosed in a transaction --- .../Java/spring-webflux/benchmark_config.json | 15 ++-- frameworks/Java/spring-webflux/pom.xml | 88 +++---------------- .../spring-webflux-jdbc.dockerfile | 6 +- .../spring-webflux-mongo.dockerfile | 6 +- .../spring-webflux-pgclient.dockerfile | 6 +- .../spring-webflux-rxjdbc.dockerfile | 6 +- .../spring-webflux/spring-webflux.dockerfile | 6 +- .../src/main/java/benchmark/App.java | 15 ++-- .../java/benchmark/config/JdbcConfig.java | 2 +- .../java/benchmark/config/PgClientConfig.java | 4 +- .../java/benchmark/config/R2dbcConfig.java | 6 +- .../benchmark/config/ReactiveMongoConfig.java | 3 +- .../java/benchmark/config/RxJdbcConfig.java | 8 +- .../repository/R2dbcDbRepository.java | 14 ++- .../java/benchmark/web/WebfluxRouter.java | 2 +- .../src/main/resources/application.yml | 48 ++++++++-- frameworks/Java/spring/pom.xml | 3 +- frameworks/Java/spring/spring-jpa.dockerfile | 23 +---- .../Java/spring/spring-mongo.dockerfile | 23 +---- frameworks/Java/spring/spring.dockerfile | 25 +----- .../Java/spring/src/main/java/hello/App.java | 2 +- .../main/java/hello/UpdateWorldService.java | 9 ++ .../java/hello/UpdateWorldServiceImpl.java | 42 +++++++++ .../hello/controller/HelloController.java | 31 +++---- .../spring/src/main/resources/application.yml | 6 +- 25 files changed, 171 insertions(+), 228 deletions(-) create mode 100644 frameworks/Java/spring/src/main/java/hello/UpdateWorldService.java create mode 100644 frameworks/Java/spring/src/main/java/hello/UpdateWorldServiceImpl.java diff --git a/frameworks/Java/spring-webflux/benchmark_config.json b/frameworks/Java/spring-webflux/benchmark_config.json index e5c13f8e292..396e9e22a1c 100644 --- a/frameworks/Java/spring-webflux/benchmark_config.json +++ b/frameworks/Java/spring-webflux/benchmark_config.json @@ -20,8 +20,7 @@ "database_os": "Linux", "display_name": "spring-webflux-r2dbc", "notes": "", - "versus": "spring", - "tags": ["broken"] + "versus": "spring" }, "mongo": { "db_url": "/db", @@ -41,8 +40,7 @@ "database_os": "Linux", "display_name": "spring-webflux-mongo", "notes": "", - "versus": "spring", - "tags": ["broken"] + "versus": "spring" }, "pgclient": { "db_url": "/db", @@ -63,8 +61,7 @@ "database_os": "Linux", "display_name": "spring-webflux-pgclient", "notes": "", - "versus": "spring", - "tags": ["broken"] + "versus": "spring" }, "rxjdbc": { "db_url": "/db", @@ -85,8 +82,7 @@ "database_os": "Linux", "display_name": "spring-webflux-rxjdbc", "notes": "", - "versus": "spring", - "tags": ["broken"] + "versus": "spring" }, "jdbc": { "db_url": "/db", @@ -107,8 +103,7 @@ "database_os": "Linux", "display_name": "spring-webflux-jdbc", "notes": "", - "versus": "spring", - "tags": ["broken"] + "versus": "spring" } }] } diff --git a/frameworks/Java/spring-webflux/pom.xml b/frameworks/Java/spring-webflux/pom.xml index 01d32c261c0..bec59f53b95 100644 --- a/frameworks/Java/spring-webflux/pom.xml +++ b/frameworks/Java/spring-webflux/pom.xml @@ -13,19 +13,14 @@ org.springframework.boot spring-boot-starter-parent - 2.2.0.M2 + 3.3.0 - 11 - 11 + 17 UTF-8 - 1.0.0.M2 - 42.7.2 0.11.4 - 0.2.4 - 1.0.0.M7 - 1.0.0.BUILD-SNAPSHOT + 0.2.14 @@ -48,7 +43,6 @@ org.postgresql postgresql - ${postgresql.version} io.reactiverse @@ -61,86 +55,25 @@ ${rxjava2-jdbc.version} - - io.r2dbc - r2dbc-postgresql - ${r2dbc-postgresql.version} - + + org.postgresql + r2dbc-postgresql + io.r2dbc r2dbc-pool - ${r2dbc-pool.version} org.springframework.data spring-data-r2dbc - ${spring-data-r2dbc.version} - - - - org.springframework - spring-tx - - - org.springframework - spring-context - - - org.springframework - spring-core - - - org.springframework - spring-beans - - - - - org.springframework - spring-tx - 5.2.0.M2 - org.springframework - spring-context - 5.2.22.BUILD-SNAPSHOT + org.springframework.boot + spring-boot-configuration-processor + true - - org.springframework - spring-core - 5.2.24.RELEASE - - - org.springframework - spring-beans - 5.2.22.BUILD-SNAPSHOT - - - - - spring-libs-snapshot - Spring Snapshots - https://repo.spring.io/libs-snapshot - - - spring-snapshots - Spring Snapshots - https://repo.spring.io/snapshot - - true - - - - - - spring-libs-snapshot - Spring Snapshots - https://repo.spring.io/libs-snapshot - - - ${project.artifactId} @@ -151,7 +84,6 @@ org.apache.maven.plugins maven-compiler-plugin - 3.8.0 false diff --git a/frameworks/Java/spring-webflux/spring-webflux-jdbc.dockerfile b/frameworks/Java/spring-webflux/spring-webflux-jdbc.dockerfile index 89f1ba40f89..7c1daea95f3 100644 --- a/frameworks/Java/spring-webflux/spring-webflux-jdbc.dockerfile +++ b/frameworks/Java/spring-webflux/spring-webflux-jdbc.dockerfile @@ -1,13 +1,13 @@ -FROM maven:3.8.5-openjdk-17-slim as maven +FROM maven:3.9.6-eclipse-temurin-21 as maven WORKDIR /spring COPY src src COPY pom.xml pom.xml RUN mvn package -q -FROM openjdk:17.0-jdk-slim +FROM eclipse-temurin:21.0.3_9-jre-jammy WORKDIR /spring COPY --from=maven /spring/target/spring-webflux-benchmark.jar app.jar EXPOSE 8080 -CMD ["java", "-server", "-XX:+UseNUMA", "-XX:+UseParallelGC", "-Dlogging.level.root=OFF", "-jar", "app.jar", "--spring.profiles.active=jdbc,postgres"] +CMD ["java", "-server", "-XX:+UseNUMA", "-Dlogging.level.root=OFF", "-jar", "app.jar", "--spring.profiles.active=jdbc,postgres"] diff --git a/frameworks/Java/spring-webflux/spring-webflux-mongo.dockerfile b/frameworks/Java/spring-webflux/spring-webflux-mongo.dockerfile index 95d24ac6003..d26a7bda983 100644 --- a/frameworks/Java/spring-webflux/spring-webflux-mongo.dockerfile +++ b/frameworks/Java/spring-webflux/spring-webflux-mongo.dockerfile @@ -1,13 +1,13 @@ -FROM maven:3.8.5-openjdk-17-slim as maven +FROM maven:3.9.6-eclipse-temurin-21 as maven WORKDIR /spring COPY src src COPY pom.xml pom.xml RUN mvn package -q -FROM openjdk:17.0-jdk-slim +FROM eclipse-temurin:21.0.3_9-jre-jammy WORKDIR /spring COPY --from=maven /spring/target/spring-webflux-benchmark.jar app.jar EXPOSE 8080 -CMD ["java", "-server", "-XX:+UseNUMA", "-XX:+UseParallelGC", "-Dlogging.level.root=OFF", "-jar", "app.jar", "--spring.profiles.active=mongo"] +CMD ["java", "-server", "-XX:+UseNUMA", "-Dlogging.level.root=OFF", "-jar", "app.jar", "--spring.profiles.active=mongo"] diff --git a/frameworks/Java/spring-webflux/spring-webflux-pgclient.dockerfile b/frameworks/Java/spring-webflux/spring-webflux-pgclient.dockerfile index 0c03140d05a..2bf38ec11e0 100644 --- a/frameworks/Java/spring-webflux/spring-webflux-pgclient.dockerfile +++ b/frameworks/Java/spring-webflux/spring-webflux-pgclient.dockerfile @@ -1,13 +1,13 @@ -FROM maven:3.8.5-openjdk-17-slim as maven +FROM maven:3.9.6-eclipse-temurin-21 as maven WORKDIR /spring COPY src src COPY pom.xml pom.xml RUN mvn package -q -FROM openjdk:17.0-jdk-slim +FROM eclipse-temurin:21.0.3_9-jre-jammy WORKDIR /spring COPY --from=maven /spring/target/spring-webflux-benchmark.jar app.jar EXPOSE 8080 -CMD ["java", "-server", "-XX:+UseNUMA", "-XX:+UseParallelGC", "-Dlogging.level.root=OFF", "-jar", "app.jar", "--spring.profiles.active=pgclient,postgres"] +CMD ["java", "-server", "-XX:+UseNUMA", "-Dlogging.level.root=OFF", "-jar", "app.jar", "--spring.profiles.active=pgclient,postgres"] diff --git a/frameworks/Java/spring-webflux/spring-webflux-rxjdbc.dockerfile b/frameworks/Java/spring-webflux/spring-webflux-rxjdbc.dockerfile index 05aacc1a8f1..0e1edfb74a9 100644 --- a/frameworks/Java/spring-webflux/spring-webflux-rxjdbc.dockerfile +++ b/frameworks/Java/spring-webflux/spring-webflux-rxjdbc.dockerfile @@ -1,13 +1,13 @@ -FROM maven:3.8.5-openjdk-17-slim as maven +FROM maven:3.9.6-eclipse-temurin-21 as maven WORKDIR /spring COPY src src COPY pom.xml pom.xml RUN mvn package -q -FROM openjdk:17.0-jdk-slim +FROM eclipse-temurin:21.0.3_9-jre-jammy WORKDIR /spring COPY --from=maven /spring/target/spring-webflux-benchmark.jar app.jar EXPOSE 8080 -CMD ["java", "-server", "-XX:+UseNUMA", "-XX:+UseParallelGC", "-Dlogging.level.root=OFF", "-jar", "app.jar", "--spring.profiles.active=rxjdbc,postgres"] +CMD ["java", "-server", "-XX:+UseNUMA", "-Dlogging.level.root=OFF", "-jar", "app.jar", "--spring.profiles.active=rxjdbc,postgres"] diff --git a/frameworks/Java/spring-webflux/spring-webflux.dockerfile b/frameworks/Java/spring-webflux/spring-webflux.dockerfile index 3d41fc1ecbe..504fb71cfae 100644 --- a/frameworks/Java/spring-webflux/spring-webflux.dockerfile +++ b/frameworks/Java/spring-webflux/spring-webflux.dockerfile @@ -1,13 +1,13 @@ -FROM maven:3.8.5-openjdk-17-slim as maven +FROM maven:3.9.6-eclipse-temurin-21 as maven WORKDIR /spring COPY src src COPY pom.xml pom.xml RUN mvn package -q -FROM openjdk:17.0-jdk-slim +FROM eclipse-temurin:21.0.3_9-jre-jammy WORKDIR /spring COPY --from=maven /spring/target/spring-webflux-benchmark.jar app.jar EXPOSE 8080 -CMD ["java", "-server", "-XX:+UseNUMA", "-XX:+UseParallelGC", "-Dlogging.level.root=OFF", "-jar", "app.jar", "--spring.profiles.active=r2dbc,postgres"] +CMD ["java", "-server", "-XX:+UseNUMA", "-Dlogging.level.root=OFF", "-jar", "app.jar", "--spring.profiles.active=r2dbc,postgres"] diff --git a/frameworks/Java/spring-webflux/src/main/java/benchmark/App.java b/frameworks/Java/spring-webflux/src/main/java/benchmark/App.java index e33025461c6..9fa3f318361 100755 --- a/frameworks/Java/spring-webflux/src/main/java/benchmark/App.java +++ b/frameworks/Java/spring-webflux/src/main/java/benchmark/App.java @@ -1,10 +1,10 @@ package benchmark; +import java.util.concurrent.Executors; + import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.boot.autoconfigure.data.mongo.MongoReactiveDataAutoConfiguration; -import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.boot.web.reactive.result.view.MustacheViewResolver; import org.springframework.context.annotation.Bean; @@ -12,12 +12,11 @@ import org.springframework.web.reactive.config.EnableWebFlux; import org.springframework.web.reactive.config.ViewResolverRegistry; import org.springframework.web.reactive.config.WebFluxConfigurer; + import reactor.core.scheduler.Scheduler; import reactor.core.scheduler.Schedulers; -import java.util.concurrent.Executors; - -@SpringBootApplication(exclude = { DataSourceAutoConfiguration.class, MongoReactiveDataAutoConfiguration.class }) +@SpringBootApplication @EnableWebFlux @EnableScheduling @EnableConfigurationProperties @@ -31,17 +30,17 @@ public static void main(String[] args) { } @Bean - public ServerFilter serverFilter() { + ServerFilter serverFilter() { return new ServerFilter(); } @Bean - public DateHandler dateHandler() { + DateHandler dateHandler() { return new DateHandler(); } @Bean - public Scheduler ioScheduler() { + Scheduler ioScheduler() { return Schedulers.fromExecutor(Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors() * 2)); } diff --git a/frameworks/Java/spring-webflux/src/main/java/benchmark/config/JdbcConfig.java b/frameworks/Java/spring-webflux/src/main/java/benchmark/config/JdbcConfig.java index cd97d6e9708..d99729490a4 100644 --- a/frameworks/Java/spring-webflux/src/main/java/benchmark/config/JdbcConfig.java +++ b/frameworks/Java/spring-webflux/src/main/java/benchmark/config/JdbcConfig.java @@ -13,7 +13,7 @@ public class JdbcConfig { @Bean - public DataSource datasource(DataSourceProperties dataSourceProperties) { + DataSource datasource(DataSourceProperties dataSourceProperties) { HikariDataSource dataSource = dataSourceProperties.initializeDataSourceBuilder().type(HikariDataSource.class).build(); dataSource.setMaximumPoolSize(Runtime.getRuntime().availableProcessors() * 2); diff --git a/frameworks/Java/spring-webflux/src/main/java/benchmark/config/PgClientConfig.java b/frameworks/Java/spring-webflux/src/main/java/benchmark/config/PgClientConfig.java index ebcbc732d67..9ebf6db60c9 100644 --- a/frameworks/Java/spring-webflux/src/main/java/benchmark/config/PgClientConfig.java +++ b/frameworks/Java/spring-webflux/src/main/java/benchmark/config/PgClientConfig.java @@ -24,12 +24,12 @@ public class PgClientConfig { private String password; @Bean - public Vertx vertx() { + Vertx vertx() { return Vertx.vertx(); } @Bean - public PgClients pgClients(Vertx vertx) { + PgClients pgClients(Vertx vertx) { List clients = new ArrayList<>(); for (int i = 0; i < Runtime.getRuntime().availableProcessors(); i++) { diff --git a/frameworks/Java/spring-webflux/src/main/java/benchmark/config/R2dbcConfig.java b/frameworks/Java/spring-webflux/src/main/java/benchmark/config/R2dbcConfig.java index 60e006cc80f..5a0de452252 100644 --- a/frameworks/Java/spring-webflux/src/main/java/benchmark/config/R2dbcConfig.java +++ b/frameworks/Java/spring-webflux/src/main/java/benchmark/config/R2dbcConfig.java @@ -9,7 +9,7 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Profile; -import org.springframework.data.r2dbc.core.DatabaseClient; +import org.springframework.r2dbc.core.DatabaseClient; import static io.r2dbc.spi.ConnectionFactoryOptions.*; @@ -44,7 +44,7 @@ public void setPassword(String password) { } @Bean - public ConnectionFactory connectionFactory() { + ConnectionFactory connectionFactory() { return ConnectionFactories.get(ConnectionFactoryOptions.builder() .option(DRIVER,"pool") .option(PROTOCOL,"postgresql") @@ -57,7 +57,7 @@ public ConnectionFactory connectionFactory() { } @Bean - public DatabaseClient databaseClient(ConnectionFactory connectionFactory) { + DatabaseClient databaseClient(ConnectionFactory connectionFactory) { return DatabaseClient.create(connectionFactory); } } \ No newline at end of file diff --git a/frameworks/Java/spring-webflux/src/main/java/benchmark/config/ReactiveMongoConfig.java b/frameworks/Java/spring-webflux/src/main/java/benchmark/config/ReactiveMongoConfig.java index ee80f0fd87b..e12178be400 100644 --- a/frameworks/Java/spring-webflux/src/main/java/benchmark/config/ReactiveMongoConfig.java +++ b/frameworks/Java/spring-webflux/src/main/java/benchmark/config/ReactiveMongoConfig.java @@ -19,6 +19,7 @@ public class ReactiveMongoConfig extends AbstractReactiveMongoConfiguration { private String url; private String name; + @Override @Bean public MongoClient reactiveMongoClient() { LoggerFactory.getLogger(getClass()).info("Connecting to mongo url: {}/{}", url, name); @@ -31,7 +32,7 @@ protected String getDatabaseName() { } @Bean - public ReactiveMongoTemplate reactiveMongoTemplate() { + ReactiveMongoTemplate reactiveMongoTemplate() { return new ReactiveMongoTemplate(reactiveMongoClient(), getDatabaseName()); } diff --git a/frameworks/Java/spring-webflux/src/main/java/benchmark/config/RxJdbcConfig.java b/frameworks/Java/spring-webflux/src/main/java/benchmark/config/RxJdbcConfig.java index 23b7d200cca..f4f5916252d 100644 --- a/frameworks/Java/spring-webflux/src/main/java/benchmark/config/RxJdbcConfig.java +++ b/frameworks/Java/spring-webflux/src/main/java/benchmark/config/RxJdbcConfig.java @@ -9,21 +9,17 @@ import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Profile; -import java.sql.SQLException; - @Configuration @Profile("rxjdbc") public class RxJdbcConfig { @Bean - public Database database(DataSourceProperties dsProps) throws SQLException { + Database database(DataSourceProperties dsProps) { NonBlockingConnectionPool pool = Pools.nonBlocking() .maxPoolSize(Runtime.getRuntime().availableProcessors() * 2) .connectionProvider(ConnectionProvider.from(dsProps.getUrl(), dsProps.getUsername(), dsProps.getPassword())) .build(); - Database db = Database.from(pool); - - return db; + return Database.from(pool); } } \ No newline at end of file diff --git a/frameworks/Java/spring-webflux/src/main/java/benchmark/repository/R2dbcDbRepository.java b/frameworks/Java/spring-webflux/src/main/java/benchmark/repository/R2dbcDbRepository.java index a6979ffb058..e5915fc05d7 100644 --- a/frameworks/Java/spring-webflux/src/main/java/benchmark/repository/R2dbcDbRepository.java +++ b/frameworks/Java/spring-webflux/src/main/java/benchmark/repository/R2dbcDbRepository.java @@ -3,7 +3,7 @@ import benchmark.model.Fortune; import benchmark.model.World; import org.springframework.context.annotation.Profile; -import org.springframework.data.r2dbc.core.DatabaseClient; +import org.springframework.r2dbc.core.DatabaseClient; import org.springframework.stereotype.Component; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; @@ -19,17 +19,16 @@ public R2dbcDbRepository(DatabaseClient databaseClient) { @Override public Mono getWorld(int id) { - return databaseClient.execute() + return databaseClient .sql("SELECT id, randomnumber FROM world WHERE id = $1") .bind("$1", id) - .as(World.class) - .fetch() + .map((row, rowMetaData) -> new World(row.get("id", Integer.class), row.get("randomnumber", Integer.class))) .first(); } public Mono updateWorld(World world) { - return databaseClient.execute() + return databaseClient .sql("UPDATE world SET randomnumber=$2 WHERE id = $1") .bind("$1", world.id) .bind("$2", world.randomnumber) @@ -47,10 +46,9 @@ public Mono findAndUpdateWorld(int id, int randomNumber) { @Override public Flux fortunes() { - return databaseClient.execute() + return databaseClient .sql("SELECT id, message FROM fortune") - .as(Fortune.class) - .fetch() + .map((row, rowMetaData) -> new Fortune(row.get("id", Integer.class), row.get("message", String.class))) .all(); } } \ No newline at end of file diff --git a/frameworks/Java/spring-webflux/src/main/java/benchmark/web/WebfluxRouter.java b/frameworks/Java/spring-webflux/src/main/java/benchmark/web/WebfluxRouter.java index b4dfb9be319..7d1ad9c881a 100644 --- a/frameworks/Java/spring-webflux/src/main/java/benchmark/web/WebfluxRouter.java +++ b/frameworks/Java/spring-webflux/src/main/java/benchmark/web/WebfluxRouter.java @@ -12,7 +12,7 @@ public class WebfluxRouter { @Bean - public RouterFunction route(WebfluxHandler handler) { + RouterFunction route(WebfluxHandler handler) { return RouterFunctions .route( GET("/plaintext"), diff --git a/frameworks/Java/spring-webflux/src/main/resources/application.yml b/frameworks/Java/spring-webflux/src/main/resources/application.yml index d45387cecde..d315f4353ee 100755 --- a/frameworks/Java/spring-webflux/src/main/resources/application.yml +++ b/frameworks/Java/spring-webflux/src/main/resources/application.yml @@ -1,6 +1,12 @@ +spring: + jpa: + open-in-view: false + --- spring: - profiles: postgres + config: + activate: + on-profile: postgres datasource: url: jdbc:postgresql://${database.host}:${database.port}/${database.name} username: ${database.username} @@ -15,23 +21,53 @@ database: --- spring: - profiles: jdbc + config: + activate: + on-profile: jdbc + autoconfigure: + exclude: + - org.springframework.boot.autoconfigure.data.mongo.MongoReactiveDataAutoConfiguration + - org.springframework.boot.autoconfigure.r2dbc.R2dbcAutoConfiguration --- spring: - profiles: pgclient + config: + activate: + on-profile: pgclient + autoconfigure: + exclude: + - org.springframework.boot.autoconfigure.data.mongo.MongoReactiveDataAutoConfiguration + - org.springframework.boot.autoconfigure.r2dbc.R2dbcAutoConfiguration --- spring: - profiles: rxjdbc + config: + activate: + on-profile: rxjdbc + autoconfigure: + exclude: + - org.springframework.boot.autoconfigure.data.mongo.MongoReactiveDataAutoConfiguration + - org.springframework.boot.autoconfigure.r2dbc.R2dbcAutoConfiguration --- spring: - profiles: r2dbc + config: + activate: + on-profile: r2dbc + autoconfigure: + exclude: + - org.springframework.boot.autoconfigure.data.mongo.MongoReactiveDataAutoConfiguration + - org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration --- spring: - profiles: mongo + config: + activate: + on-profile: mongo + autoconfigure: + exclude: + - org.springframework.boot.autoconfigure.r2dbc.R2dbcAutoConfiguration + - org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration database: url: mongodb://tfb-database:27017/?waitQueueMultiple=200 diff --git a/frameworks/Java/spring/pom.xml b/frameworks/Java/spring/pom.xml index b646277a3b0..4e390ebc4f6 100644 --- a/frameworks/Java/spring/pom.xml +++ b/frameworks/Java/spring/pom.xml @@ -11,12 +11,11 @@ org.springframework.boot spring-boot-starter-parent - 3.0.0 + 3.3.0 17 - 42.5.1 diff --git a/frameworks/Java/spring/spring-jpa.dockerfile b/frameworks/Java/spring/spring-jpa.dockerfile index 4c197667a24..4af1b98a73f 100644 --- a/frameworks/Java/spring/spring-jpa.dockerfile +++ b/frameworks/Java/spring/spring-jpa.dockerfile @@ -1,30 +1,11 @@ -FROM eclipse-temurin:17 as jre-build - -# Create a custom Java runtime -RUN $JAVA_HOME/bin/jlink \ - --add-modules ALL-MODULE-PATH \ - --strip-debug \ - --no-man-pages \ - --no-header-files \ - --compress=2 \ - --output /javaruntime - -FROM maven:3.8.5-openjdk-17-slim as maven -ENV JAVA_HOME=/opt/java/openjdk -ENV PATH "${JAVA_HOME}/bin:${PATH}" -COPY --from=jre-build /javaruntime $JAVA_HOME - +FROM maven:3.9.6-eclipse-temurin-21 as maven RUN mvn -version WORKDIR /spring COPY src src COPY pom.xml pom.xml RUN mvn package -q -FROM debian:bullseye-slim -ENV JAVA_HOME=/opt/java/openjdk -ENV PATH "${JAVA_HOME}/bin:${PATH}" -COPY --from=jre-build /javaruntime $JAVA_HOME - +FROM eclipse-temurin:21.0.3_9-jre-jammy RUN java -version WORKDIR /spring COPY --from=maven /spring/target/hello-spring-1.0-SNAPSHOT.jar app.jar diff --git a/frameworks/Java/spring/spring-mongo.dockerfile b/frameworks/Java/spring/spring-mongo.dockerfile index 3672481ca61..4fa82a28d5d 100644 --- a/frameworks/Java/spring/spring-mongo.dockerfile +++ b/frameworks/Java/spring/spring-mongo.dockerfile @@ -1,30 +1,11 @@ -FROM eclipse-temurin:17 as jre-build - -# Create a custom Java runtime -RUN $JAVA_HOME/bin/jlink \ - --add-modules ALL-MODULE-PATH \ - --strip-debug \ - --no-man-pages \ - --no-header-files \ - --compress=2 \ - --output /javaruntime - -FROM maven:3.8.5-openjdk-17-slim as maven -ENV JAVA_HOME=/opt/java/openjdk -ENV PATH "${JAVA_HOME}/bin:${PATH}" -COPY --from=jre-build /javaruntime $JAVA_HOME - +FROM maven:3.9.6-eclipse-temurin-21 as maven RUN mvn -version WORKDIR /spring COPY src src COPY pom.xml pom.xml RUN mvn package -q -FROM debian:bullseye-slim -ENV JAVA_HOME=/opt/java/openjdk -ENV PATH "${JAVA_HOME}/bin:${PATH}" -COPY --from=jre-build /javaruntime $JAVA_HOME - +FROM eclipse-temurin:21.0.3_9-jre-jammy RUN java -version WORKDIR /spring COPY --from=maven /spring/target/hello-spring-1.0-SNAPSHOT.jar app.jar diff --git a/frameworks/Java/spring/spring.dockerfile b/frameworks/Java/spring/spring.dockerfile index a06133e8c45..f6f5145477f 100644 --- a/frameworks/Java/spring/spring.dockerfile +++ b/frameworks/Java/spring/spring.dockerfile @@ -1,34 +1,15 @@ -FROM eclipse-temurin:17 as jre-build - -# Create a custom Java runtime -RUN $JAVA_HOME/bin/jlink \ - --add-modules ALL-MODULE-PATH \ - --strip-debug \ - --no-man-pages \ - --no-header-files \ - --compress=2 \ - --output /javaruntime - -FROM maven:3.8.5-openjdk-17-slim as maven -ENV JAVA_HOME=/opt/java/openjdk -ENV PATH "${JAVA_HOME}/bin:${PATH}" -COPY --from=jre-build /javaruntime $JAVA_HOME - +FROM maven:3.9.6-eclipse-temurin-21 as maven RUN mvn -version WORKDIR /spring COPY src src COPY pom.xml pom.xml RUN mvn package -q -FROM debian:bullseye-slim -ENV JAVA_HOME=/opt/java/openjdk -ENV PATH "${JAVA_HOME}/bin:${PATH}" -COPY --from=jre-build /javaruntime $JAVA_HOME - +FROM eclipse-temurin:21.0.3_9-jre-jammy RUN java -version WORKDIR /spring COPY --from=maven /spring/target/hello-spring-1.0-SNAPSHOT.jar app.jar EXPOSE 8080 -CMD ["java", "-server", "-XX:+UseNUMA", "-XX:+UseG1GC", "-XX:+DisableExplicitGC", "-XX:+UseStringDeduplication", "-Dlogging.level.root=OFF", "-jar", "app.jar", "--spring.profiles.active=jdbc"] +CMD ["java", "-server", "-XX:+UseNUMA", "-XX:+DisableExplicitGC", "-XX:+UseStringDeduplication", "-Dlogging.level.root=OFF", "-jar", "app.jar", "--spring.profiles.active=jdbc"] diff --git a/frameworks/Java/spring/src/main/java/hello/App.java b/frameworks/Java/spring/src/main/java/hello/App.java index e8e93b65902..0ab1327f8c4 100644 --- a/frameworks/Java/spring/src/main/java/hello/App.java +++ b/frameworks/Java/spring/src/main/java/hello/App.java @@ -28,7 +28,7 @@ public void runAfterStartup() { @Bean @Profile({ "jdbc", "jpa" }) - public DataSource datasource(DataSourceProperties dataSourceProperties) { + DataSource datasource(DataSourceProperties dataSourceProperties) { HikariDataSource dataSource = dataSourceProperties.initializeDataSourceBuilder().type(HikariDataSource.class) .build(); dataSource.setMaximumPoolSize(Runtime.getRuntime().availableProcessors() * 2); diff --git a/frameworks/Java/spring/src/main/java/hello/UpdateWorldService.java b/frameworks/Java/spring/src/main/java/hello/UpdateWorldService.java new file mode 100644 index 00000000000..11c6568c076 --- /dev/null +++ b/frameworks/Java/spring/src/main/java/hello/UpdateWorldService.java @@ -0,0 +1,9 @@ +package hello; + +import hello.model.World; + +public interface UpdateWorldService { + + World updateWorld(int worldId); + +} diff --git a/frameworks/Java/spring/src/main/java/hello/UpdateWorldServiceImpl.java b/frameworks/Java/spring/src/main/java/hello/UpdateWorldServiceImpl.java new file mode 100644 index 00000000000..b59680aef5c --- /dev/null +++ b/frameworks/Java/spring/src/main/java/hello/UpdateWorldServiceImpl.java @@ -0,0 +1,42 @@ +package hello; + +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import hello.controller.HelloController; +import hello.model.World; +import hello.repository.DbRepository; + +@Service +public class UpdateWorldServiceImpl implements UpdateWorldService { + + private DbRepository dbRepository; + + public UpdateWorldServiceImpl(DbRepository dbRepository) { + this.dbRepository = dbRepository; + } + + @Override + @Transactional + public World updateWorld(int worldId) { + var world = dbRepository.getWorld(worldId); + // Ensure that the new random number is not equal to the old one. + // That would cause the JPA-based implementation to avoid sending the + // UPDATE query to the database, which would violate the test + // requirements. + + // Locally the records doesn't exist, maybe in the yours is ok but we need to + // make this check + if (world == null) { + return null; + } + + int newRandomNumber; + do { + newRandomNumber = HelloController.randomWorldNumber(); + } while (newRandomNumber == world.randomnumber); + + return dbRepository.updateWorld(world, newRandomNumber); + } + +} diff --git a/frameworks/Java/spring/src/main/java/hello/controller/HelloController.java b/frameworks/Java/spring/src/main/java/hello/controller/HelloController.java index 6046a2e7426..3c891567942 100644 --- a/frameworks/Java/spring/src/main/java/hello/controller/HelloController.java +++ b/frameworks/Java/spring/src/main/java/hello/controller/HelloController.java @@ -13,6 +13,7 @@ import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; +import hello.UpdateWorldService; import hello.model.Fortune; import hello.model.World; import hello.repository.DbRepository; @@ -21,9 +22,13 @@ public final class HelloController { private DbRepository dbRepository; + private UpdateWorldService updateWorldService; - public HelloController(DbRepository dbRepository) { + public HelloController( + DbRepository dbRepository, + UpdateWorldService updateWorldService) { this.dbRepository = dbRepository; + this.updateWorldService = updateWorldService; } @GetMapping(value = "/plaintext") @@ -54,25 +59,9 @@ World[] queries(HttpServletResponse response, @RequestParam(required = false) St @GetMapping("/updates") World[] updates(HttpServletResponse response, @RequestParam(required = false) String queries) { response.setContentType(MediaType.APPLICATION_JSON_VALUE); - return randomWorldNumbers().mapToObj(dbRepository::getWorld).map(world -> { - // Ensure that the new random number is not equal to the old one. - // That would cause the JPA-based implementation to avoid sending the - // UPDATE query to the database, which would violate the test - // requirements. - - // Locally the records doesn't exist, maybe in the yours is ok but we need to - // make this check - if (world == null) { - return null; - } - - int newRandomNumber; - do { - newRandomNumber = randomWorldNumber(); - } while (newRandomNumber == world.randomnumber); - - return dbRepository.updateWorld(world, newRandomNumber); - }).limit(parseQueryCount(queries)).toArray(World[]::new); + return randomWorldNumbers() + .mapToObj(id -> updateWorldService.updateWorld(id)) + .limit(parseQueryCount(queries)).toArray(World[]::new); } @GetMapping("/fortunes") @@ -89,7 +78,7 @@ List fortunes(HttpServletResponse response) { private static final int MIN_WORLD_NUMBER = 1; private static final int MAX_WORLD_NUMBER_PLUS_ONE = 10_001; - private static int randomWorldNumber() { + public static int randomWorldNumber() { return ThreadLocalRandom.current().nextInt(MIN_WORLD_NUMBER, MAX_WORLD_NUMBER_PLUS_ONE); } diff --git a/frameworks/Java/spring/src/main/resources/application.yml b/frameworks/Java/spring/src/main/resources/application.yml index 0f411d6d8e9..42c14602858 100644 --- a/frameworks/Java/spring/src/main/resources/application.yml +++ b/frameworks/Java/spring/src/main/resources/application.yml @@ -1,5 +1,10 @@ --- spring: + threads: + virtual: + enabled: true + jpa: + open-in-view: false config: activate: on-profile: jdbc,jpa @@ -22,7 +27,6 @@ spring: on-profile: jpa jpa: database-platform: org.hibernate.dialect.PostgreSQLDialect - open-in-view: false --- spring: From bd015859fa65e3223c928d397db2c832865ae1bf Mon Sep 17 00:00:00 2001 From: Petrik de Heus Date: Mon, 8 Jul 2024 17:26:41 +0200 Subject: [PATCH 012/204] [ruby|rack-sequel] Use OJ for faster json serialization. (#9147) --- frameworks/Ruby/rack-sequel/Gemfile | 1 + frameworks/Ruby/rack-sequel/hello_world.rb | 11 +++++++---- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/frameworks/Ruby/rack-sequel/Gemfile b/frameworks/Ruby/rack-sequel/Gemfile index fb4b4ad65d8..22e0dd418b8 100644 --- a/frameworks/Ruby/rack-sequel/Gemfile +++ b/frameworks/Ruby/rack-sequel/Gemfile @@ -1,6 +1,7 @@ source 'https://rubygems.org' gem 'json', '~> 2.0' +gem 'oj', '~> 3.14', platforms: %i[ruby mswin] gem 'passenger', '~> 6.0', :platforms=>[:ruby, :mswin], :require=>false gem 'puma', '~> 6.4', :require=>false gem 'sequel', '~> 5.0' diff --git a/frameworks/Ruby/rack-sequel/hello_world.rb b/frameworks/Ruby/rack-sequel/hello_world.rb index d68de1f48d7..6fc3a787975 100644 --- a/frameworks/Ruby/rack-sequel/hello_world.rb +++ b/frameworks/Ruby/rack-sequel/hello_world.rb @@ -1,5 +1,8 @@ # frozen_string_literal: true +require 'oj' +Oj.mimic_JSON + # Our Rack application to be executed by rackup class HelloWorld DEFAULT_HEADERS = {}.tap do |h| @@ -91,19 +94,19 @@ def call(env) case env['PATH_INFO'] when '/json' # Test type 1: JSON serialization - [JSON_TYPE, JSON.fast_generate(message: 'Hello, World!')] + [JSON_TYPE, { message: 'Hello, World!' }.to_json] when '/db' # Test type 2: Single database query - [JSON_TYPE, JSON.fast_generate(db)] + [JSON_TYPE, db.to_json] when '/queries' # Test type 3: Multiple database queries - [JSON_TYPE, JSON.fast_generate(queries(env))] + [JSON_TYPE, queries(env).to_json] when '/fortunes' # Test type 4: Fortunes [HTML_TYPE, fortunes] when '/updates' # Test type 5: Database updates - [JSON_TYPE, JSON.fast_generate(updates(env))] + [JSON_TYPE, updates(env).to_json] when '/plaintext' # Test type 6: Plaintext [PLAINTEXT_TYPE, 'Hello, World!'] From 14c71fdc30b0da386a6927ff9d98aa083994fdfc Mon Sep 17 00:00:00 2001 From: Petrik de Heus Date: Mon, 8 Jul 2024 17:26:50 +0200 Subject: [PATCH 013/204] [ruby|sinatra] Use batch update on postgres (#9143) --- frameworks/Ruby/sinatra/Gemfile | 12 ++++++------ frameworks/Ruby/sinatra/boot.rb | 14 ++++++++++++-- frameworks/Ruby/sinatra/hello_world.rb | 25 +++++++++++++------------ 3 files changed, 31 insertions(+), 20 deletions(-) diff --git a/frameworks/Ruby/sinatra/Gemfile b/frameworks/Ruby/sinatra/Gemfile index 22752eec379..ff34570a2cb 100644 --- a/frameworks/Ruby/sinatra/Gemfile +++ b/frameworks/Ruby/sinatra/Gemfile @@ -1,16 +1,16 @@ source 'https://rubygems.org' -gem 'activerecord', '~> 7.0', :require=>'active_record' +gem 'activerecord', '~> 7.1', require: 'active_record' gem 'oj' -gem 'passenger', '~> 6.0', :platforms=>[:ruby, :mswin], :require=>false -gem 'puma', '~> 6.4', :require=>false -gem 'sinatra', '~> 3.0', :require=>'sinatra/base' -gem 'unicorn', '~> 6.1', :platforms=>[:ruby, :mswin], :require=>false +gem 'passenger', '~> 6.0', platforms: [:ruby, :mswin], require: false +gem 'puma', '~> 6.4', require: false +gem 'sinatra', '~> 3.0', require: 'sinatra/base' +gem 'unicorn', '~> 6.1', platforms: [:ruby, :mswin], require: false group :mysql do gem 'mysql2', '~> 0.5', :platforms=>[:ruby, :mswin] end group :postgresql do - gem 'pg', '~> 1.5', :platforms=>[:ruby, :mswin] + gem 'pg', '~> 1.5', platforms: [:ruby, :mswin] end diff --git a/frameworks/Ruby/sinatra/boot.rb b/frameworks/Ruby/sinatra/boot.rb index 355fc53df74..97fa0c40bdb 100644 --- a/frameworks/Ruby/sinatra/boot.rb +++ b/frameworks/Ruby/sinatra/boot.rb @@ -58,8 +58,18 @@ def connect(dbtype) class World < ActiveRecord::Base self.table_name = name - alias_attribute(:randomnumber, :randomNumber) \ - if connection.adapter_name.downcase.start_with?('mysql') + alias_attribute(:randomNumber, :randomnumber) \ + if connection.adapter_name.downcase.start_with?('postgres') + + if connection.adapter_name.downcase.start_with?('mysql') + def self.upsert_all(attributes, on_duplicate: :update, update_only: nil, returning: nil, unique_by: nil, record_timestamps: nil) + # On MySQL Batch updates verification isn't supported yet by TechEmpower. + # https://github.com/TechEmpower/FrameworkBenchmarks/issues/5983 + attributes.each do |attrs| + where(id: attrs[:id]).update_all(randomNumber: attrs[:randomNumber]) + end + end + end end class Fortune < ActiveRecord::Base diff --git a/frameworks/Ruby/sinatra/hello_world.rb b/frameworks/Ruby/sinatra/hello_world.rb index 90238498ed2..328fa402921 100644 --- a/frameworks/Ruby/sinatra/hello_world.rb +++ b/frameworks/Ruby/sinatra/hello_world.rb @@ -45,7 +45,7 @@ def rand1 # Test type 1: JSON serialization get '/json' do - json :message=>'Hello, World!' + json message: 'Hello, World!' end # Test type 2: Single database query @@ -76,27 +76,28 @@ def rand1 Fortune.all end.to_a @fortunes << Fortune.new( - :id=>0, - :message=>'Additional fortune added at request time.' + id: 0, + message: 'Additional fortune added at request time.' ) @fortunes.sort_by!(&:message) - erb :fortunes, :layout=>true + erb :fortunes, layout: true end # Test type 5: Database updates get '/updates' do worlds = - ActiveRecord::Base.connection_pool.with_connection do - ALL_IDS.sample(bounded_queries).map do |id| - world = World.find(id) - new_value = rand1 - new_value = rand1 while new_value == world.randomnumber - world.update_columns(randomnumber: new_value) - world.attributes + ALL_IDS.sample(bounded_queries).map do |id| + world = ActiveRecord::Base.connection_pool.with_connection do + World.find(id) end + new_value = rand1 + new_value = rand1 until new_value != world.randomNumber + { id: id, randomNumber: new_value } end - + ActiveRecord::Base.connection_pool.with_connection do + World.upsert_all(worlds.sort_by!{_1[:id]}) + end json worlds end From 3661938ab43508bde64f90c2491ab5b774ff9b5a Mon Sep 17 00:00:00 2001 From: Petrik de Heus Date: Mon, 8 Jul 2024 17:27:01 +0200 Subject: [PATCH 014/204] [ruby/rack] Upgrade Rack to latest version (#9140) --- frameworks/Ruby/rack/Gemfile.lock | 60 +++++++++++++++---------------- 1 file changed, 29 insertions(+), 31 deletions(-) diff --git a/frameworks/Ruby/rack/Gemfile.lock b/frameworks/Ruby/rack/Gemfile.lock index 75e57b3ea0e..0fa04f72580 100644 --- a/frameworks/Ruby/rack/Gemfile.lock +++ b/frameworks/Ruby/rack/Gemfile.lock @@ -2,37 +2,36 @@ GEM remote: https://rubygems.org/ specs: ast (2.4.2) - async (2.11.0) + async (2.12.1) console (~> 1.25, >= 1.25.2) fiber-annotation - io-event (~> 1.5, >= 1.5.1) - timers (~> 4.1) + io-event (~> 1.6, >= 1.6.5) async-container (0.18.2) async (~> 2.10) - async-http (0.66.3) + async-http (0.69.0) async (>= 2.10.2) - async-pool (>= 0.6.1) - io-endpoint (~> 0.10, >= 0.10.3) + async-pool (~> 0.7) + io-endpoint (~> 0.11) io-stream (~> 0.4) - protocol-http (~> 0.26.0) - protocol-http1 (~> 0.19.0) - protocol-http2 (~> 0.17.0) - traces (>= 0.10.0) + protocol-http (~> 0.26) + protocol-http1 (~> 0.19) + protocol-http2 (~> 0.18) + traces (>= 0.10) async-http-cache (0.4.3) async-http (~> 0.56) - async-pool (0.6.1) + async-pool (0.7.0) async (>= 1.25) async-service (0.12.0) async async-container (~> 0.16) bigdecimal (3.1.8) - concurrent-ruby (1.2.3) + concurrent-ruby (1.3.3) connection_pool (2.4.1) console (1.25.2) fiber-annotation fiber-local (~> 1.1) json - falcon (0.47.6) + falcon (0.47.7) async async-container (~> 0.18) async-http (~> 0.66, >= 0.66.3) @@ -47,9 +46,9 @@ GEM fiber-annotation (0.2.0) fiber-local (1.1.0) fiber-storage - fiber-storage (0.1.0) - io-endpoint (0.10.3) - io-event (1.5.1) + fiber-storage (0.1.2) + io-endpoint (0.11.0) + io-event (1.6.5) io-stream (0.4.0) json (2.7.2) kgio (2.11.4) @@ -57,11 +56,11 @@ GEM localhost (1.3.1) mapping (1.1.1) nio4r (2.7.3) - oj (3.16.3) + oj (3.16.4) bigdecimal (>= 3.0) openssl (3.2.0) - parallel (1.24.0) - parser (3.3.1.0) + parallel (1.25.1) + parser (3.3.3.0) ast (~> 2.4.1) racc pg (1.5.6) @@ -69,27 +68,27 @@ GEM console (~> 1.8) samovar (~> 2.1) protocol-hpack (1.4.3) - protocol-http (0.26.5) + protocol-http (0.26.6) protocol-http1 (0.19.1) protocol-http (~> 0.22) - protocol-http2 (0.17.0) + protocol-http2 (0.18.0) protocol-hpack (~> 1.4) protocol-http (~> 0.18) - protocol-rack (0.5.1) + protocol-rack (0.6.0) protocol-http (~> 0.23) rack (>= 1.0) puma (6.4.2) nio4r (~> 2.0) - racc (1.7.3) - rack (3.0.11) + racc (1.8.0) + rack (3.1.6) rack-test (2.1.0) rack (>= 1.3) rainbow (3.1.1) raindrops (0.20.1) - regexp_parser (2.9.1) - rexml (3.2.8) - strscan (>= 3.0.9) - rubocop (1.63.5) + regexp_parser (2.9.2) + rexml (3.3.1) + strscan + rubocop (1.64.1) json (~> 2.3) language_server-protocol (>= 3.17.0) parallel (~> 1.10) @@ -106,13 +105,12 @@ GEM samovar (2.3.0) console (~> 1.0) mapping (~> 1.0) - sequel (5.80.0) + sequel (5.82.0) bigdecimal sequel_pg (1.17.1) pg (>= 0.18.0, != 1.2.0) sequel (>= 4.38.0) strscan (3.1.0) - timers (4.3.5) traces (0.11.1) tzinfo (2.0.6) concurrent-ruby (~> 1.0) @@ -145,4 +143,4 @@ DEPENDENCIES unicorn (~> 6.1) BUNDLED WITH - 2.4.10 + 2.5.11 From bec7f74cb49b04a8a86d4d46003e9d17205a59fa Mon Sep 17 00:00:00 2001 From: kanarus Date: Tue, 9 Jul 2024 00:27:12 +0900 Subject: [PATCH 015/204] update ohkami to v0.19, dependencies & refactor some (#9120) --- frameworks/Rust/ohkami/Cargo.lock | 22 +++++++++++----------- frameworks/Rust/ohkami/Cargo.toml | 6 +++--- frameworks/Rust/ohkami/README.md | 2 +- frameworks/Rust/ohkami/ohkami.dockerfile | 2 +- frameworks/Rust/ohkami/src/postgres.rs | 9 +++------ 5 files changed, 19 insertions(+), 22 deletions(-) diff --git a/frameworks/Rust/ohkami/Cargo.lock b/frameworks/Rust/ohkami/Cargo.lock index b0bc7617d71..95d46009a5b 100644 --- a/frameworks/Rust/ohkami/Cargo.lock +++ b/frameworks/Rust/ohkami/Cargo.lock @@ -770,9 +770,9 @@ dependencies = [ [[package]] name = "ohkami" -version = "0.18.2" +version = "0.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d810447a32af4750a45183a4915db5ca4183bb6d44b8e7731e63f627c581d93e" +checksum = "e598d3d323527b920e159d55da2754067a5edfbc0678d60b3886fc379f4637f2" dependencies = [ "byte_reader", "hmac", @@ -787,7 +787,7 @@ dependencies = [ [[package]] name = "ohkami_framework_benchmarks" -version = "0.18.2" +version = "0.19.0" dependencies = [ "futures-util", "ohkami", @@ -799,9 +799,9 @@ dependencies = [ [[package]] name = "ohkami_lib" -version = "0.2.3" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4433e6c4c6c67a72afc306783ca8c641e69c9d171279fcab51f1f0c2d875e121" +checksum = "05fdeee00f86ee850c63a15068f2c2a3aeb6d707d4936f2261ec0e70ff48704b" dependencies = [ "byte_reader", "percent-encoding", @@ -810,9 +810,9 @@ dependencies = [ [[package]] name = "ohkami_macros" -version = "0.7.3" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffed4cd7e8c12a62c077273cb0f0fedf67ca3912488e5de1b325be85ca86bb06" +checksum = "d5fa46d8805dede76dce71f8725d48d655f74e2c702824f7a785257d1cc4dd1b" dependencies = [ "proc-macro2", "quote", @@ -1574,9 +1574,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.37.0" +version = "1.38.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1adbebffeca75fcfd058afa480fb6c0b81e165a0323f9c9d39c9697e37c46787" +checksum = "ba4f4a02a7a80d6f274636f0aa95c7e383b912d41fe721a31f29e29698585a4a" dependencies = [ "backtrace", "bytes", @@ -1593,9 +1593,9 @@ dependencies = [ [[package]] name = "tokio-macros" -version = "2.2.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" +checksum = "5f5ae998a069d4b5aba8ee9dad856af7d520c3699e6159b185c2acd48155d39a" dependencies = [ "proc-macro2", "quote", diff --git a/frameworks/Rust/ohkami/Cargo.toml b/frameworks/Rust/ohkami/Cargo.toml index 8a168f5c413..b6bf50cf97c 100644 --- a/frameworks/Rust/ohkami/Cargo.toml +++ b/frameworks/Rust/ohkami/Cargo.toml @@ -1,12 +1,12 @@ [package] name = "ohkami_framework_benchmarks" -version = "0.18.2" +version = "0.19.0" edition = "2021" authors = ["kanarus "] [dependencies] -ohkami = { version = "=0.18.2", features = ["rt_tokio"] } -tokio = { version = "1.37.0" , features = ["full"] } +ohkami = { version = "=0.19.0", features = ["rt_tokio"] } +tokio = { version = "1.38.0" , features = ["full"] } rand = { version = "0.8.5" , features = ["small_rng"] } sqlx = { version = "0.7.4" , features = ["postgres", "macros", "runtime-tokio-native-tls"] } yarte = { version = "0.15.7" } diff --git a/frameworks/Rust/ohkami/README.md b/frameworks/Rust/ohkami/README.md index 21b85f2cc50..d9fda426ed3 100644 --- a/frameworks/Rust/ohkami/README.md +++ b/frameworks/Rust/ohkami/README.md @@ -1,4 +1,4 @@ -# [ohkami](https://github.com/kana-rus/ohkami) - Intuitive and Declarative Web Framework for Rust +# [Ohkami](https://github.com/kana-rus/ohkami) - Intuitive and Declarative Web Framework for Rust ## Description diff --git a/frameworks/Rust/ohkami/ohkami.dockerfile b/frameworks/Rust/ohkami/ohkami.dockerfile index 97a69dd07ae..b993ec905a5 100644 --- a/frameworks/Rust/ohkami/ohkami.dockerfile +++ b/frameworks/Rust/ohkami/ohkami.dockerfile @@ -1,4 +1,4 @@ -FROM rust:1.78-slim-buster +FROM rust:1.79-slim-buster WORKDIR /ohkami_framework_benchmarks ENV DATABASE_URL=postgres://benchmarkdbuser:benchmarkdbpass@tfb-database/hello_world diff --git a/frameworks/Rust/ohkami/src/postgres.rs b/frameworks/Rust/ohkami/src/postgres.rs index 7f29317d1ba..e9238d67493 100644 --- a/frameworks/Rust/ohkami/src/postgres.rs +++ b/frameworks/Rust/ohkami/src/postgres.rs @@ -16,16 +16,14 @@ impl Postgres { pub async fn select_random_world(&self) -> World { let mut rng = SmallRng::from_rng(&mut thread_rng()).unwrap(); - sqlx::query_as( - "SELECT id, randomnumber FROM World WHERE id = $1") + sqlx::query_as("SELECT id, randomnumber FROM World WHERE id = $1") .bind((rng.gen::() % 10_000 + 1) as i32) .fetch_one(&self.0).await .expect("Failed to fetch a world") } pub async fn select_all_fortunes(&self) -> Vec { - sqlx::query_as( - "SELECT id, message FROM Fortune") + sqlx::query_as("SELECT id, message FROM Fortune") .fetch_all(&self.0).await .expect("Failed to fetch fortunes") } @@ -36,8 +34,7 @@ impl Postgres { let selects = FuturesUnordered::new(); for _ in 0..n { selects.push( - sqlx::query_as( - "SELECT id, randomnumber FROM World WHERE id = $1") + sqlx::query_as("SELECT id, randomnumber FROM World WHERE id = $1") .bind((rng.gen::() % 10_000 + 1) as i32) .fetch_one(&self.0) ) From b9ced2e628825736093bc234da171a456c5f88d9 Mon Sep 17 00:00:00 2001 From: Vladimir Shchur Date: Mon, 8 Jul 2024 18:27:45 +0300 Subject: [PATCH 016/204] [F#/Oxpecker] Changed db type from micro-ORM to raw + refactoring (#9118) * [F#/Oxpecker] Switched from Dapper to raw ADO (cherry picked from commit 2f386186a28f7dc502a3d3c7da35211e12d395f0) * [F#/Oxpecker] Refactoring * [F#/Oxpecker] Updated Readme * [F#/Oxpecker] Updated Readme * [F#/Oxpecker] Fixed "versus" field --- frameworks/FSharp/oxpecker/README.md | 11 +- .../FSharp/oxpecker/benchmark_config.json | 4 +- frameworks/FSharp/oxpecker/config.toml | 4 +- frameworks/FSharp/oxpecker/src/App/App.fsproj | 3 +- frameworks/FSharp/oxpecker/src/App/Common.fs | 34 ++++++ frameworks/FSharp/oxpecker/src/App/Db.fs | 104 +++++++++++++++++ frameworks/FSharp/oxpecker/src/App/Program.fs | 109 +++--------------- 7 files changed, 162 insertions(+), 107 deletions(-) create mode 100644 frameworks/FSharp/oxpecker/src/App/Common.fs create mode 100644 frameworks/FSharp/oxpecker/src/App/Db.fs diff --git a/frameworks/FSharp/oxpecker/README.md b/frameworks/FSharp/oxpecker/README.md index ecd2284661d..3d8a00a248a 100644 --- a/frameworks/FSharp/oxpecker/README.md +++ b/frameworks/FSharp/oxpecker/README.md @@ -1,5 +1,5 @@ # Oxpecker Tests on Linux -This includes tests for plaintext, json, and fortunes HTML serialization. +This includes tests for plaintext, json, fortunes, single query, mutliple queries and data updates. ## Infrastructure Software Versions @@ -18,9 +18,6 @@ This includes tests for plaintext, json, and fortunes HTML serialization. **Web Stack** * [Oxpecker](https://github.com/Lanayx/Oxpecker) -* [Dapper](https://github.com/DapperLib/Dapper) -* ASP.NET Core - -## Paths & Source for Tests - -All source code is inside `Program.fs`. +* [Npgsql](https://github.com/npgsql/npgsql) +* [System.Text.Json](https://github.com/dotnet/runtime/tree/main/src/libraries/System.Text.Json) +* ASP.NET Core \ No newline at end of file diff --git a/frameworks/FSharp/oxpecker/benchmark_config.json b/frameworks/FSharp/oxpecker/benchmark_config.json index c0df28d86a3..562c9514420 100644 --- a/frameworks/FSharp/oxpecker/benchmark_config.json +++ b/frameworks/FSharp/oxpecker/benchmark_config.json @@ -15,7 +15,7 @@ "database": "Postgres", "framework": "Oxpecker", "language": "F#", - "orm": "Micro", + "orm": "Raw", "platform": ".NET", "flavor": "CoreCLR", "webserver": "Kestrel", @@ -23,7 +23,7 @@ "database_os": "Linux", "display_name": "Oxpecker", "notes": "", - "versus": "aspcore" + "versus": "aspnetcore" } } ] diff --git a/frameworks/FSharp/oxpecker/config.toml b/frameworks/FSharp/oxpecker/config.toml index dd5e34c8b96..75e7f904754 100644 --- a/frameworks/FSharp/oxpecker/config.toml +++ b/frameworks/FSharp/oxpecker/config.toml @@ -13,7 +13,7 @@ classification = "fullstack" database = "Postgres" database_os = "Linux" os = "Linux" -orm = "micro" +orm = "Raw" platform = ".NET" webserver = "Kestrel" -versus = "aspcore" \ No newline at end of file +versus = "aspnetcore" \ No newline at end of file diff --git a/frameworks/FSharp/oxpecker/src/App/App.fsproj b/frameworks/FSharp/oxpecker/src/App/App.fsproj index a9e0ad2c0ba..f01c367f95f 100644 --- a/frameworks/FSharp/oxpecker/src/App/App.fsproj +++ b/frameworks/FSharp/oxpecker/src/App/App.fsproj @@ -6,12 +6,13 @@ + + - diff --git a/frameworks/FSharp/oxpecker/src/App/Common.fs b/frameworks/FSharp/oxpecker/src/App/Common.fs new file mode 100644 index 00000000000..0b62abdefee --- /dev/null +++ b/frameworks/FSharp/oxpecker/src/App/Common.fs @@ -0,0 +1,34 @@ +namespace App + +open System +open System.Collections.Generic + +[] +module Common = + + [] + [] + type JsonMessage = { + message : string + } + + [] + type Fortune = { + id: int + message: string + } + + [] + [] + type World = { + id: int + randomnumber: int + } + + [] + let ConnectionString = "Server=tfb-database;Database=hello_world;User Id=benchmarkdbuser;Password=benchmarkdbpass;SSL Mode=Disable;Maximum Pool Size=1024;NoResetOnClose=true;Enlist=false;Max Auto Prepare=4;Multiplexing=true;Write Coalescing Buffer Threshold Bytes=1000" + + let FortuneComparer = { + new IComparer with + member self.Compare(a,b) = String.CompareOrdinal(a.message, b.message) + } diff --git a/frameworks/FSharp/oxpecker/src/App/Db.fs b/frameworks/FSharp/oxpecker/src/App/Db.fs new file mode 100644 index 00000000000..498721b2b2e --- /dev/null +++ b/frameworks/FSharp/oxpecker/src/App/Db.fs @@ -0,0 +1,104 @@ +namespace App + +open System +open System.Data +open System.Data.Common +open System.Text +open Npgsql + + +[] +module Db = + let loadFortunes () = + let result = ResizeArray() + task { + use db = new NpgsqlConnection(ConnectionString) + use cmd = db.CreateCommand(CommandText = "SELECT id, message FROM fortune") + do! db.OpenAsync() + use! rdr = cmd.ExecuteReaderAsync(CommandBehavior.CloseConnection) + while! rdr.ReadAsync() do + result.Add { id = rdr.GetInt32(0); message = rdr.GetString(1) } + return result + } + + let private createReadCommand (connection: DbConnection) = + let cmd = connection.CreateCommand( + CommandText = "SELECT id, randomnumber FROM world WHERE id = @Id" + ) + let id = cmd.CreateParameter( + ParameterName = "@Id", + DbType = DbType.Int32, + Value = Random.Shared.Next(1, 10001) + ) + cmd.Parameters.Add(id) |> ignore + cmd + + let private readSingleRow (cmd: DbCommand) = + task { + use! rdr = cmd.ExecuteReaderAsync(CommandBehavior.SingleRow) + let! _ = rdr.ReadAsync() + return { id = rdr.GetInt32(0); randomnumber = rdr.GetInt32(1) } + } + + let loadSingleRow () = + task { + use db = new NpgsqlConnection(ConnectionString) + do! db.OpenAsync() + use cmd = createReadCommand db + return! readSingleRow cmd + } + + let private readMultipleRows (count: int) (conn: NpgsqlConnection) = + let result = Array.zeroCreate count + task { + use cmd = createReadCommand conn + for i in 0..result.Length-1 do + cmd.Parameters["@Id"].Value <- Random.Shared.Next(1, 10001) + let! row = readSingleRow cmd + result[i] <- row + return result + } + + let loadMultipleRows (count: int) = + task { + use db = new NpgsqlConnection(ConnectionString) + do! db.OpenAsync() + return! readMultipleRows count db + } + + let private maxBatch = 500 + let private queries = Array.zeroCreate (maxBatch + 1) + let private batchUpdateString batchSize = + match queries[batchSize] with + | null -> + let lastIndex = batchSize - 1 + let sb = StringBuilder() + sb.Append("UPDATE world SET randomNumber = temp.randomNumber FROM (VALUES ") |> ignore + for i in 0..lastIndex-1 do + sb.AppendFormat("(@Id_{0}, @Rn_{0}), ", i) |> ignore + sb.AppendFormat("(@Id_{0}, @Rn_{0}) ORDER BY 1) AS temp(id, randomNumber) WHERE temp.id = world.id", lastIndex) |> ignore + let result = sb.ToString() + queries[batchSize] <- result + result + | q -> + q + + let private generateParameters (results: World[]) (command: DbCommand) = + for i in 0..results.Length-1 do + let randomNumber = Random.Shared.Next(1, 10001) + let random = command.CreateParameter(ParameterName = $"@Rn_{i}", DbType = DbType.Int32, Value = randomNumber) + command.Parameters.Add(random) |> ignore + let id = command.CreateParameter(ParameterName = $"@Id_{i}", DbType = DbType.Int32, Value = results[i].id) + command.Parameters.Add(id) |> ignore + results[i] <- { results[i] with randomnumber = randomNumber } + + let doMultipleUpdates (count: int) = + task { + use conn = new NpgsqlConnection(ConnectionString) + do! conn.OpenAsync() + let! results = readMultipleRows count conn + use cmd = conn.CreateCommand(CommandText = batchUpdateString count) + do generateParameters results cmd + let! _ = cmd.ExecuteNonQueryAsync() + return results + } diff --git a/frameworks/FSharp/oxpecker/src/App/Program.fs b/frameworks/FSharp/oxpecker/src/App/Program.fs index bdb95afa593..dcfd3c53206 100644 --- a/frameworks/FSharp/oxpecker/src/App/Program.fs +++ b/frameworks/FSharp/oxpecker/src/App/Program.fs @@ -1,32 +1,8 @@ namespace App open System -open System.Collections.Generic open Oxpecker -[] -module Common = - - [] - [] - type JsonMessage = { - message : string - } - - [] - type Fortune = { - id: int - message: string - } - - [] - let ConnectionString = "Server=tfb-database;Database=hello_world;User Id=benchmarkdbuser;Password=benchmarkdbpass;SSL Mode=Disable;Maximum Pool Size=1024;NoResetOnClose=true;Enlist=false;Max Auto Prepare=4;Multiplexing=true;Write Coalescing Buffer Threshold Bytes=1000" - - let FortuneComparer = { - new IComparer with - member self.Compare(a,b) = String.CompareOrdinal(a.message, b.message) - } - [] module HtmlViews = open Oxpecker.ViewEngine @@ -48,7 +24,7 @@ module HtmlViews = th() { raw "message" } } - let fortunes fortunesData = + let fortunes (fortunesData: ResizeArray) = table() { fortunesTableHeader for fortune in fortunesData do @@ -60,8 +36,6 @@ module HtmlViews = [] module HttpHandlers = - open Dapper - open Npgsql open System.Text open Microsoft.AspNetCore.Http open System.Text.Json @@ -72,32 +46,24 @@ module HttpHandlers = message = "Additional fortune added at request time." } - let rec private renderFortunes (ctx: HttpContext) (dbFortunes: Fortune seq) = - let data = dbFortunes.AsList() + let rec private renderFortunes (ctx: HttpContext) (data: ResizeArray) = data.Add extra data.Sort FortuneComparer data |> HtmlViews.fortunes |> ctx.WriteHtmlView - let private fortunes : EndpointHandler = + let fortunes : EndpointHandler = fun ctx -> task { - use conn = new NpgsqlConnection(ConnectionString) - let! dbFortunes = conn.QueryAsync("SELECT id, message FROM fortune") + let! dbFortunes = loadFortunes () return! renderFortunes ctx dbFortunes } - [] - [] - type World = { - id: int - randomnumber: int - } - - let private readSingleRow (conn: NpgsqlConnection) = - conn.QueryFirstOrDefaultAsync( - "SELECT id, randomnumber FROM world WHERE id = @Id", - {| Id = Random.Shared.Next(1, 10001) |} - ) + let singleQuery : EndpointHandler = + fun ctx -> + task { + let! result = loadSingleRow() + return! ctx.WriteJsonChunked result + } let private parseQueries (ctx: HttpContext) = match ctx.TryGetRouteValue("count") with @@ -107,66 +73,19 @@ module HttpHandlers = | _, _ -> 1 | _ -> 1 - let private singleQuery : EndpointHandler = - fun ctx -> - task { - use conn = new NpgsqlConnection(ConnectionString) - let! result = readSingleRow conn - return! ctx.WriteJsonChunked result - } - - let private multipleQueries : EndpointHandler = + let multipleQueries : EndpointHandler = fun ctx -> let count = parseQueries ctx - let results = Array.zeroCreate count task { - use conn = new NpgsqlConnection(ConnectionString) - do! conn.OpenAsync() - for i in 0..results.Length-1 do - let! result = readSingleRow conn - results[i] <- result + let! results = loadMultipleRows count return! ctx.WriteJsonChunked results } - let private maxBatch = 500 - let private queries = Array.zeroCreate (maxBatch + 1) - - let private batchUpdateString batchSize = - match queries[batchSize] with - | null -> - let lastIndex = batchSize - 1 - let sb = StringBuilder() - sb.Append("UPDATE world SET randomNumber = temp.randomNumber FROM (VALUES ") |> ignore - for i in 0..lastIndex-1 do - sb.AppendFormat("(@Id_{0}, @Rn_{0}), ", i) |> ignore - sb.AppendFormat("(@Id_{0}, @Rn_{0}) ORDER BY 1) AS temp(id, randomNumber) WHERE temp.id = world.id", lastIndex) |> ignore - let result = sb.ToString() - queries[batchSize] <- result - result - | q -> - q - - let private generateParameters (results: World[]) = - let parameters = Dictionary() - for i in 0..results.Length-1 do - let randomNumber = Random.Shared.Next(1, 10001) - parameters[$"@Rn_{i}"] <- randomNumber - parameters[$"@Id_{i}"] <- results[i].id - results[i] <- { results[i] with randomnumber = randomNumber } - parameters - - let private multipleUpdates : EndpointHandler = + let multipleUpdates : EndpointHandler = fun ctx -> let count = parseQueries ctx - let results = Array.zeroCreate count task { - use conn = new NpgsqlConnection(ConnectionString) - do! conn.OpenAsync() - for i in 0..results.Length-1 do - let! result = readSingleRow conn - results[i] <- result - let parameters = generateParameters results - let! _ = conn.ExecuteAsync(batchUpdateString count, parameters) + let! results = doMultipleUpdates count return! ctx.WriteJsonChunked results } From 67dcfb7764f73439d83c2b9b3e658711fdad5a58 Mon Sep 17 00:00:00 2001 From: Bartosz Jarzyna <44323413+bbrtj@users.noreply.github.com> Date: Mon, 8 Jul 2024 17:28:04 +0200 Subject: [PATCH 017/204] Perl Kelp: Fix and modernize (#9115) * Perl Kelp: Fix and modernize * Perl Kelp: benchmark on multiple web servers * Perl Kelp: unfreeze framework version, a couple of fixes --- frameworks/Perl/kelp/README.md | 45 +++-- frameworks/Perl/kelp/app.ini | 3 +- frameworks/Perl/kelp/app.pl | 145 ---------------- frameworks/Perl/kelp/app.psgi | 8 + frameworks/Perl/kelp/benchmark_config.json | 168 +++++++++++++++++-- frameworks/Perl/kelp/conf/config.pl | 12 ++ frameworks/Perl/kelp/conf/test.pl | 23 +++ frameworks/Perl/kelp/config.toml | 32 ---- frameworks/Perl/kelp/kelp-mongodb.dockerfile | 27 --- frameworks/Perl/kelp/kelp.dockerfile | 40 +++-- frameworks/Perl/kelp/lib/KelpBench.pm | 130 ++++++++++++++ frameworks/Perl/kelp/lib/KelpBench/DBI.pm | 47 ++++++ frameworks/Perl/kelp/lib/KelpBench/Mongo.pm | 43 +++++ frameworks/Perl/kelp/run.pl | 78 +++++++++ frameworks/Perl/kelp/t/main.t | 111 ++++++++---- frameworks/Perl/kelp/views/fortunes.tt | 22 +++ 16 files changed, 659 insertions(+), 275 deletions(-) delete mode 100755 frameworks/Perl/kelp/app.pl create mode 100755 frameworks/Perl/kelp/app.psgi create mode 100644 frameworks/Perl/kelp/conf/config.pl create mode 100644 frameworks/Perl/kelp/conf/test.pl delete mode 100644 frameworks/Perl/kelp/config.toml delete mode 100644 frameworks/Perl/kelp/kelp-mongodb.dockerfile create mode 100644 frameworks/Perl/kelp/lib/KelpBench.pm create mode 100644 frameworks/Perl/kelp/lib/KelpBench/DBI.pm create mode 100644 frameworks/Perl/kelp/lib/KelpBench/Mongo.pm create mode 100755 frameworks/Perl/kelp/run.pl create mode 100644 frameworks/Perl/kelp/views/fortunes.tt diff --git a/frameworks/Perl/kelp/README.md b/frameworks/Perl/kelp/README.md index f66a3470d67..8be16d73c02 100644 --- a/frameworks/Perl/kelp/README.md +++ b/frameworks/Perl/kelp/README.md @@ -1,18 +1,17 @@ # Setup -* Perl 5.10+ -* MySQL 5.5 -* MongoDB -* Wrk 2.0 +* Perl 5.36+ +* MariaDB or MongoDB # Requirements * Kelp (install from CPAN) -* Kelp::Module::JSON::XS (install from CPAN) * Kelp::Module::Template::Toolkit (install from CPAN) -* DBD::mysql (install from CPAN) +* DBI + DBD::mysql or MongoDB (install from CPAN) +* Gazelle (install from CPAN) * Starman (install from CPAN) -* MongoDB (install from CPAN) +* Starlet (install from CPAN) +* Twiggy::Prefork (install from CPAN) * nginx (if you want to front with nginx, nginx.conf provided) # Deployment @@ -24,16 +23,38 @@ ./uwsgi --plugins psgi --init app.ini -## Plack + Starman +## Plack + plack handler -1. Deploy via plackup +Recommended handler is `Gazelle`. - plackup -E deployment -s Starman --workers=25 -l /tmp/frameworks-benchmark.sock -a ./app.pl +1. Deploy via `start_server`, if you want to front it with nginx. -2. If you want to front it with nginx, otherwise + start_server --path /tmp/perl-kelp.sock --backlog 16384 -- plackup -E production -s Gazelle --max-workers=25 --max-reqs-per-child=10000 -a ./app.psgi - plackup -E deployment -s Starman --port=8080 --workers=25 -a ./app.pl +2. Otherwise + + plackup -E deployment -s Gazelle --port=8080 --max-workers=25 -a ./app.psgi + +# Code information + +`lib/KelpBench.pm` contains all action-handling and helper code. It is a full +Kelp app with `Template::Toolkit` module and standard Kelp configuration files. +While it could've been coded as a one-file Kelp app, full app style gives us +more control on the behavior of the app. It lazy-loads `DBI.pm` or `Mongo.pm` +from `lib/KelpBench/` directory based on environmental variable `MONGO`, so it +only needs one database driver at a time. + +The app is written in a relaxed style, not trying very hard to achieve the best +possible result. It very much resembles production code. For example, a proper +templating engine is used to produce the HTML document instead of inline HTML +(which is obviously much faster). + +App can be tested using mock database by running `prove -l`. In this case, it +only requires `Kelp` and `Kelp::Module::Template::Toolkit` from CPAN to be +installed. # Expert contact +@bbrtj (contact@bbrtj.eu) @naturalist (minimal@cpan.org) + diff --git a/frameworks/Perl/kelp/app.ini b/frameworks/Perl/kelp/app.ini index 7a53ad301ae..ebeb49abedf 100644 --- a/frameworks/Perl/kelp/app.ini +++ b/frameworks/Perl/kelp/app.ini @@ -1,4 +1,5 @@ [uwsgi] http-socket = :8080 -psgi = app.pl +psgi = app.psgi disable-logging = True + diff --git a/frameworks/Perl/kelp/app.pl b/frameworks/Perl/kelp/app.pl deleted file mode 100755 index 8db36540926..00000000000 --- a/frameworks/Perl/kelp/app.pl +++ /dev/null @@ -1,145 +0,0 @@ -#!/usr/bin/env perl - -use Kelp::Less; -use HTML::Escape 'escape_html'; -use MongoDB; -use DBI; -use utf8; - -module 'JSON::XS'; - -my $mongo; -my $mdb; -my $world; -my $fortune; -my @sth; -my $dbh; - -if ($ENV{MONGO}) { - $mongo = MongoDB::MongoClient->new( host => 'tfb-database', port => 27017 ); - $mdb = $mongo->get_database('hello_world'); - $world = $mdb->get_collection('world'); - $fortune = $mdb->get_collection('fortune'); -} else { - $dbh = DBI->connect( - "dbi:mysql:database=hello_world;host=tfb-database;port=3306", - 'benchmarkdbuser', - 'benchmarkdbpass', - { RaiseError => 0, PrintError => 0, mysql_enable_utf8 => 1 } - ); - @sth = map { $dbh->prepare($_) } ( - "SELECT * FROM World WHERE id = ?", - "SELECT * FROM Fortune", - "UPDATE World SET randomNumber = ? WHERE id = ?", - ); -} - -get '/json' => sub { - { message => 'Hello, World!' }; -}; - -get '/db/?db' => sub { - my ( $self, $db ) = @_; - my $id = int rand 10000 + 1; - my $row; - if ( $db eq 'mongo' ) { - $row = $world->find_one( { _id => $id } ); - } - else { - $sth[0]->execute($id); - $row = $sth[0]->fetchrow_hashref; - } - return { id => $id, randomNumber => $row->{randomNumber} }; -}; - -get '/queries/?db' => sub { - my ( $self, $db ) = @_; - query( $db // 'mongo', $self->param('queries') ); -}; - -get '/fortunes/?db' => sub { - my ( $self, $db ) = @_; - $db //= 'mongo'; - my @objects; - if ( $db eq 'mongo' ) { - my $cursor = $fortune->query( {} ); - @objects = $cursor->all; - } - else { - $sth[1]->execute(); - @objects = @{ $sth[1]->fetchall_arrayref( {} ) }; - } - push @objects, { id => 0, message => "Additional fortune added at request time." }; - fortunes( \@objects ); -}; - -get '/update/?db' => sub { - my ( $self, $db ) = @_; - $db //= 'mongo'; - - my $arr = query( $db, $self->param('queries') ); - $arr = [$arr] unless ref($arr) eq 'ARRAY'; - for my $row (@$arr) { - $row->{randomNumber} = int( rand(10_000) ) + 1; - if ( $db eq 'mongo' ) { - $world->update( { _id => $row->{id} }, - { randomNumber => $row->{randomNumber} } ); - } - else { - $row->{randomNumber} = int( rand(10_000) ) + 1; - $sth[2]->execute( $row->{randomNumber}, $row->{id} ); - } - } - - return $arr; -}; - -get '/plaintext' => sub { - shift->res->text->render('Hello, World!'); -}; - -run; - -sub query { - my ( $db, $count ) = @_; - $count //= 1; - $count = 1 if ( $count !~ /^\d+$/ || $count < 1 ); - $count = 500 if $count > 500; - my @response; - for ( 1 .. $count ) { - my $id = int rand 10000 + 1; - my $row; - if ( $db eq 'mongo' ) { - $row = $world->find_one( { _id => $id } ); - } - else { - $sth[0]->execute($id); - $row = $sth[0]->fetchrow_hashref; - } - if ($row) { - push @response, - { id => $id, randomNumber => $row->{randomNumber} }; - } - } - return \@response; -} - -sub fortunes { - my ($objects) = @_; - my $res = q[Fortunes]; - $res .= q[]; - - for my $item ( sort { $a->{message} cmp $b->{message} } @$objects ) { - my $id = $item->{id}; - my $message = escape_html( $item->{message} ); - - # HTML::Escape encodes apostrophe as ' because IE8 does not - # support '. We forse an ' here in order to pass the - # test - $message =~ s/'/&apos/g; - $res .= ""; - } - - $res .= q[
idmessage
$id$message
]; - return $res; -} diff --git a/frameworks/Perl/kelp/app.psgi b/frameworks/Perl/kelp/app.psgi new file mode 100755 index 00000000000..5a8182549bd --- /dev/null +++ b/frameworks/Perl/kelp/app.psgi @@ -0,0 +1,8 @@ +#!/usr/bin/env perl + +use Path::Tiny qw(path); +use lib path(__FILE__)->parent->child('lib'); +use KelpBench; + +KelpBench->new->run; + diff --git a/frameworks/Perl/kelp/benchmark_config.json b/frameworks/Perl/kelp/benchmark_config.json index 036f68fd31f..1cd06f51ad0 100644 --- a/frameworks/Perl/kelp/benchmark_config.json +++ b/frameworks/Perl/kelp/benchmark_config.json @@ -1,11 +1,61 @@ { "framework": "kelp", "tests": [{ - "default": { - "db_url": "/db/mysql", - "query_url": "/queries/mysql?queries=", - "fortune_url": "/fortunes/mysql", + "gazelle-mysql": { + "dockerfile": "kelp.dockerfile", "plaintext_url": "/plaintext", + "json_url": "/json", + "db_url": "/db", + "query_url": "/queries?queries=", + "update_url": "/updates?queries=", + "fortune_url": "/fortunes", + "port": 8080, + "approach": "Realistic", + "classification": "Fullstack", + "database": "MySQL", + "framework": "kelp", + "language": "Perl", + "orm": "Raw", + "platform": "Plack", + "webserver": "Gazelle", + "os": "Linux", + "database_os": "Linux", + "notes": "", + "versus": "", + "tags": [] + }, + "gazelle-mongodb": { + "dockerfile": "kelp.dockerfile", + "plaintext_url": "/plaintext", + "json_url": "/json", + "db_url": "/db", + "query_url": "/queries?queries=", + "update_url": "/updates?queries=", + "fortune_url": "/fortunes", + "port": 8080, + "approach": "Realistic", + "classification": "Fullstack", + "database": "MongoDB", + "framework": "kelp", + "language": "Perl", + "orm": "Raw", + "platform": "Plack", + "webserver": "Gazelle", + "os": "Linux", + "database_os": "Linux", + "notes": "", + "versus": "", + "tags": [] + }, + + "starman-mysql": { + "dockerfile": "kelp.dockerfile", + "plaintext_url": "/plaintext", + "json_url": "/json", + "db_url": "/db", + "query_url": "/queries?queries=", + "update_url": "/updates?queries=", + "fortune_url": "/fortunes", "port": 8080, "approach": "Realistic", "classification": "Fullstack", @@ -17,16 +67,18 @@ "webserver": "Starman", "os": "Linux", "database_os": "Linux", - "display_name": "kelp", "notes": "", "versus": "", - "tags": ["broken"] + "tags": [] }, - "mongodb": { - "db_url": "/db/mongo", - "query_url": "/queries/mongo?queries=", - "fortune_url": "/fortunes/mongo", + "starman-mongodb": { + "dockerfile": "kelp.dockerfile", "plaintext_url": "/plaintext", + "json_url": "/json", + "db_url": "/db", + "query_url": "/queries?queries=", + "update_url": "/updates?queries=", + "fortune_url": "/fortunes", "port": 8080, "approach": "Realistic", "classification": "Fullstack", @@ -38,10 +90,102 @@ "webserver": "Starman", "os": "Linux", "database_os": "Linux", - "display_name": "kelp", "notes": "", "versus": "", - "tags": ["broken"] + "tags": [] + }, + + "starlet-mysql": { + "dockerfile": "kelp.dockerfile", + "plaintext_url": "/plaintext", + "json_url": "/json", + "db_url": "/db", + "query_url": "/queries?queries=", + "update_url": "/updates?queries=", + "fortune_url": "/fortunes", + "port": 8080, + "approach": "Realistic", + "classification": "Fullstack", + "database": "MySQL", + "framework": "kelp", + "language": "Perl", + "orm": "Raw", + "platform": "Plack", + "webserver": "Starlet", + "os": "Linux", + "database_os": "Linux", + "notes": "", + "versus": "", + "tags": [] + }, + "starlet-mongodb": { + "dockerfile": "kelp.dockerfile", + "plaintext_url": "/plaintext", + "json_url": "/json", + "db_url": "/db", + "query_url": "/queries?queries=", + "update_url": "/updates?queries=", + "fortune_url": "/fortunes", + "port": 8080, + "approach": "Realistic", + "classification": "Fullstack", + "database": "MongoDB", + "framework": "kelp", + "language": "Perl", + "orm": "Raw", + "platform": "Plack", + "webserver": "Starlet", + "os": "Linux", + "database_os": "Linux", + "notes": "", + "versus": "", + "tags": [] + }, + + "twiggy-mysql": { + "dockerfile": "kelp.dockerfile", + "plaintext_url": "/plaintext", + "json_url": "/json", + "db_url": "/db", + "query_url": "/queries?queries=", + "fortune_url": "/fortunes", + "port": 8080, + "approach": "Realistic", + "classification": "Fullstack", + "database": "MySQL", + "framework": "kelp", + "language": "Perl", + "orm": "Raw", + "platform": "Plack", + "webserver": "Twiggy", + "os": "Linux", + "database_os": "Linux", + "notes": "", + "versus": "", + "tags": [] + }, + "twiggy-mongodb": { + "dockerfile": "kelp.dockerfile", + "plaintext_url": "/plaintext", + "json_url": "/json", + "db_url": "/db", + "query_url": "/queries?queries=", + "fortune_url": "/fortunes", + "port": 8080, + "approach": "Realistic", + "classification": "Fullstack", + "database": "MongoDB", + "framework": "kelp", + "language": "Perl", + "orm": "Raw", + "platform": "Plack", + "webserver": "Twiggy", + "os": "Linux", + "database_os": "Linux", + "notes": "", + "versus": "", + "tags": [] } }] } + diff --git a/frameworks/Perl/kelp/conf/config.pl b/frameworks/Perl/kelp/conf/config.pl new file mode 100644 index 00000000000..ce7f3527f59 --- /dev/null +++ b/frameworks/Perl/kelp/conf/config.pl @@ -0,0 +1,12 @@ +{ + modules => [qw(JSON Template::Toolkit)], + modules_init => { + 'Template::Toolkit' => { + STRICT => 1, + OUTLINE_TAG => qr{\V*%%}, # https://github.com/abw/Template2/issues/320 + ENCODING => 'utf8', + INCLUDE_PATH => 'views', + }, + }, +} + diff --git a/frameworks/Perl/kelp/conf/test.pl b/frameworks/Perl/kelp/conf/test.pl new file mode 100644 index 00000000000..f480597ed9b --- /dev/null +++ b/frameworks/Perl/kelp/conf/test.pl @@ -0,0 +1,23 @@ +{ + '+modules' => [qw(Logger)], + + modules_init => { + Logger => { + outputs => [ + [ + 'Screen', + name => 'logs', + min_level => 'debug', + stderr => 1, + newline => 1, + utf8 => 1, + ], + ], + }, + + 'Template::Toolkit' => { + DEBUG => 1, + }, + }, +} + diff --git a/frameworks/Perl/kelp/config.toml b/frameworks/Perl/kelp/config.toml deleted file mode 100644 index 7e997486fb2..00000000000 --- a/frameworks/Perl/kelp/config.toml +++ /dev/null @@ -1,32 +0,0 @@ -[framework] -name = "kelp" - -[main] -urls.plaintext = "/plaintext" -urls.db = "/db/mysql" -urls.query = "/queries/mysql?queries=" -urls.fortune = "/fortunes/mysql" -approach = "Realistic" -classification = "Fullstack" -database = "MySQL" -database_os = "Linux" -os = "Linux" -orm = "Raw" -platform = "Plack" -webserver = "Starman" -versus = "" - -[mongodb] -urls.plaintext = "/plaintext" -urls.db = "/db/mongo" -urls.query = "/queries/mongo?queries=" -urls.fortune = "/fortunes/mongo" -approach = "Realistic" -classification = "Fullstack" -database = "MongoDB" -database_os = "Linux" -os = "Linux" -orm = "Raw" -platform = "Plack" -webserver = "Starman" -versus = "" diff --git a/frameworks/Perl/kelp/kelp-mongodb.dockerfile b/frameworks/Perl/kelp/kelp-mongodb.dockerfile deleted file mode 100644 index 783c7e4d263..00000000000 --- a/frameworks/Perl/kelp/kelp-mongodb.dockerfile +++ /dev/null @@ -1,27 +0,0 @@ -FROM perl:5.26 - -RUN apt-get update -yqq && apt-get install -yqq nginx - -WORKDIR /kelp - -RUN cpanm --notest --no-man-page \ - JSON JSON::XS IO::Socket::IP IO::Socket::SSL \ - Kelp@0.9071 \ - DBI@1.636 \ - DBD::mysql@4.033 \ - MongoDB@1.8.1 \ - Kelp::Module::JSON::XS@0.502 \ - HTML::Escape@1.10 \ - HTTP::Parser::XS@0.17 \ - Starman@0.4014 - -ADD ./app.ini /kelp/ -ADD ./app.pl /kelp/ -ADD ./nginx.conf /kelp/ - -ENV MONGO=1 - -EXPOSE 8080 - -CMD nginx -c /kelp/nginx.conf && \ - plackup -E production -s Starman --workers=$(nproc) -l /tmp/perl-kelp.sock -a ./app.pl diff --git a/frameworks/Perl/kelp/kelp.dockerfile b/frameworks/Perl/kelp/kelp.dockerfile index 7bfd6f33521..b8bd3453317 100644 --- a/frameworks/Perl/kelp/kelp.dockerfile +++ b/frameworks/Perl/kelp/kelp.dockerfile @@ -1,25 +1,33 @@ -FROM perl:5.26 +FROM perl:5.40 + +ARG TFB_TEST_NAME +ARG TFB_TEST_DATABASE RUN apt-get update -yqq && apt-get install -yqq nginx WORKDIR /kelp RUN cpanm --notest --no-man-page \ - JSON JSON::XS IO::Socket::IP IO::Socket::SSL \ - Kelp@0.9071 \ - DBI@1.636 \ - DBD::mysql@4.033 \ - MongoDB@1.8.1 \ - Kelp::Module::JSON::XS@0.502 \ - HTML::Escape@1.10 \ - HTTP::Parser::XS@0.17 \ - Starman@0.4014 - -ADD ./app.ini /kelp/ -ADD ./app.pl /kelp/ -ADD ./nginx.conf /kelp/ + Kelp::Module::Template::Toolkit@0.301 \ + Kelp \ + DBI@1.643 \ + DBD::MariaDB@1.23 \ + MongoDB@2.2.2 \ + Cpanel::JSON::XS@4.38 \ + Gazelle@0.49 \ + Starman@0.4017 \ + Starlet@0.31 \ + Twiggy::Prefork@0.08 \ + Net::Server::SS::PreFork@0.05 + +ADD ./ /kelp/ + +ENV TEST_NAME=$TFB_TEST_NAME +ENV DATABASE=$TFB_TEST_DATABASE +ENV MAX_REQS=100000 +ENV SOCKET_FILE=/tmp/perl-kelp.sock EXPOSE 8080 -CMD nginx -c /kelp/nginx.conf && \ - plackup -E production -s Starman --workers=$(nproc) -l /tmp/perl-kelp.sock -a ./app.pl +CMD nginx -c /kelp/nginx.conf && ./run.pl + diff --git a/frameworks/Perl/kelp/lib/KelpBench.pm b/frameworks/Perl/kelp/lib/KelpBench.pm new file mode 100644 index 00000000000..d20a72a31ed --- /dev/null +++ b/frameworks/Perl/kelp/lib/KelpBench.pm @@ -0,0 +1,130 @@ +package KelpBench; + +use v5.36; +use Kelp::Base 'Kelp'; + +## Attributes + +attr database => sub { + if (lc $ENV{DATABASE} eq 'mongodb') { + require KelpBench::Mongo; + return KelpBench::Mongo->new; + } + elsif (lc $ENV{DATABASE} eq 'mysql') { + require KelpBench::DBI; + return KelpBench::DBI->new; + } + else { + die "unknown database chosen: $ENV{DATABASE}"; + } +}; + +## Utilities + +sub validate_number ($self, $num, $min, $max) +{ + return $min unless length($num // '') && $num !~ /\D/; + return $min if $num < $min; + return $max if $num > $max; + return $num; +} + +sub random_number ($self, $max = 10_000) +{ + return int(rand($max) + 1); +} + +sub random_id ($self) +{ + # in case random ids were not the same as random numbers + return $self->random_number(10_000); +} + +sub get_random_entries ($self, $count) +{ + $count = $self->validate_number($count, 1, 500); + + my @result; + for (1 .. $count) { + my $id = $self->random_id; + my $row = $self->database->random_number($id); + next unless $row; + + push @result, { + id => $id, + randomNumber => $row->{randomNumber} + }; + } + + return \@result; +} + +## Framework code + +sub before_dispatch {} # skip trying to log access +sub before_finalize {} # skip adding X-Framework + +sub build ($self) +{ + $self->add_route([GET => '/plaintext'] => 'action_plaintext'); + $self->add_route([GET => '/json'] => 'action_json'); + $self->add_route([GET => '/db'] => 'action_db'); + $self->add_route([GET => '/queries'] => 'action_queries'); + $self->add_route([GET => '/fortunes'] => 'action_fortunes'); + $self->add_route([GET => '/updates'] => 'action_updates'); +} + +## Registered route handlers +## Names prefixed with _action, because we did not separate a controller +## (Controllers would slow this down a bit due to reblessing of app object) + +sub action_plaintext ($self) +{ + $self->res->text; + return 'Hello, World!'; +} + +sub action_json ($self) +{ + return { message => 'Hello, World!' }; +} + +sub action_db ($self) +{ + my $id = $self->random_id; + my $row = $self->database->random_number($id); + + return { id => $id, randomNumber => $row->{randomNumber} }; +} + +sub action_queries ($self) +{ + return $self->get_random_entries($self->req->query_param('queries')); +} + +sub action_fortunes ($self) { + my $objects = $self->database->fortune; + + push $objects->@*, { + id => 0, + message => "Additional fortune added at request time." + }; + + $objects->@* = sort { $a->{message} cmp $b->{message} } $objects->@*; + return $self->template('fortunes', { rows => $objects }); +} + +sub action_updates ($self) +{ + my $arr = $self->get_random_entries($self->req->query_param('queries')); + + foreach my $row ($arr->@*) { + $row->{randomNumber} = $self->random_number; + $self->database->update($row->@{qw(id randomNumber)}); + } + + return $arr; +}; + +1; + diff --git a/frameworks/Perl/kelp/lib/KelpBench/DBI.pm b/frameworks/Perl/kelp/lib/KelpBench/DBI.pm new file mode 100644 index 00000000000..15440bff07e --- /dev/null +++ b/frameworks/Perl/kelp/lib/KelpBench/DBI.pm @@ -0,0 +1,47 @@ +package KelpBench::DBI; + +use v5.36; +use Kelp::Base 'Kelp'; +use DBI; + +attr dbh => sub { + DBI->connect( + "dbi:MariaDB:database=hello_world;host=tfb-database;port=3306", + 'benchmarkdbuser', + 'benchmarkdbpass', + { RaiseError => 1, PrintError => 0 } + ); +}; + +attr _world => sub ($self) { + $self->dbh->prepare("SELECT * FROM World WHERE id = ?"); +}; + +attr _fortune => sub ($self) { + $self->dbh->prepare("SELECT * FROM Fortune"); +}; + +attr _update => sub ($self) { + $self->dbh->prepare("UPDATE World SET randomNumber = ? WHERE id = ?"); +}; + +sub random_number ($self, $id) +{ + $self->_world->execute($id); + return $self->_world->fetchrow_hashref; +} + +sub fortune ($self) +{ + $self->_fortune->execute(); + return $self->_fortune->fetchall_arrayref({}); +} + +sub update ($self, $id, $random_number) +{ + $self->_update->execute($random_number, $id); + return; +} + +1; + diff --git a/frameworks/Perl/kelp/lib/KelpBench/Mongo.pm b/frameworks/Perl/kelp/lib/KelpBench/Mongo.pm new file mode 100644 index 00000000000..3af50e54c12 --- /dev/null +++ b/frameworks/Perl/kelp/lib/KelpBench/Mongo.pm @@ -0,0 +1,43 @@ +package KelpBench::Mongo; + +use v5.36; +use Kelp::Base 'Kelp'; +use MongoDB; + +attr dbh => sub { + MongoDB::MongoClient->new( + host => 'tfb-database', + port => 27017 + )->get_database('hello_world'); +}; + +attr _world => sub ($self) { + $self->dbh->get_collection('world'); +}; + +attr _fortune => sub ($self) { + $self->dbh->get_collection('fortune'); +}; + +sub random_number ($self, $id) +{ + return $self->_world->find_one({ _id => $id }); +} + +sub fortune ($self) +{ + return [$self->_fortune->find->all]; +} + +sub update ($self, $id, $random_number) +{ + $self->_world->update_one( + { _id => $id }, + { '$set' => { randomNumber => $random_number } }, + ); + + return; +} + +1; + diff --git a/frameworks/Perl/kelp/run.pl b/frameworks/Perl/kelp/run.pl new file mode 100755 index 00000000000..b8436498f64 --- /dev/null +++ b/frameworks/Perl/kelp/run.pl @@ -0,0 +1,78 @@ +#!/usr/bin/env perl + +use v5.36; +use Data::Dumper; + +my $max_reqs = $ENV{MAX_REQS}; +my $test_name = $ENV{TEST_NAME}; +my $socket_file = $ENV{SOCKET_FILE}; +my $app_runner = 'app.psgi'; + +my $max_workers = `nproc`; +chomp $max_workers; + +my %runner_map = ( + gazelle => [ + 'start_server', + '--path' => $socket_file, + '--backlog' => 16384, + '--', + 'plackup', + '-E' => 'production', + '-s' => 'Gazelle', + '--max-workers' => $max_workers, + '--max-reqs-per-child' => $max_reqs, + '-a' => $app_runner, + ], + starman => [ + 'start_server', + '--backlog' => 16384, + '--', + 'plackup', + '-E' => 'production', + '-s' => 'Starman', + '-l' => $socket_file, + '--workers' => $max_workers, + '--max-requests' => $max_reqs, + '-a' => $app_runner, + ], + starlet => [ + 'start_server', + '--path' => $socket_file, + '--backlog' => 16384, + '--', + 'plackup', + '-E' => 'production', + '-s' => 'Starlet', + '--max-workers' => $max_workers, + '--max-reqs-per-child' => $max_reqs, + '-a' => $app_runner, + ], + # NOTE: twiggy does not play well with Server::Starter + # NOTE: twiggy couldn't pass update tests, so I disabled them + twiggy => [ + 'plackup', + '-E' => 'production', + '-s' => 'Twiggy::Prefork', + '-l' => $socket_file, + '--backlog' => 16384, + '--max-workers' => $max_workers, + '--max-reqs-per-child' => $max_reqs, + '-a' => $app_runner, + ], +); + +die "invalid test name $test_name" + unless $test_name =~ m{^kelp-(\w+)-(\w+)$}; + +die 'database mismatch' + unless $2 eq $ENV{DATABASE}; + +my $command = $runner_map{$1}; +die "invalid server $1" + unless $command; + +say 'Running command: ' . Dumper($command); + +exec @$command; + diff --git a/frameworks/Perl/kelp/t/main.t b/frameworks/Perl/kelp/t/main.t index 8d816c95324..a682ca112cf 100644 --- a/frameworks/Perl/kelp/t/main.t +++ b/frameworks/Perl/kelp/t/main.t @@ -1,56 +1,107 @@ -use strict; -use warnings; +use v5.36; use utf8; use Kelp::Test; use Test::More; use Test::Deep; use HTTP::Request::Common; +use KelpBench; -my $t = Kelp::Test->new( psgi => 'app.pl'); -my $world = { randomNumber => re(qr{^\d+$}), id => re(qr{^\d+$}) }; +# use mock to avoid the need for DB modules and actual running DB +# (however, we do not test for DB code correctness this way) +package DBMock { + use v5.36; + use utf8; -subtest 'json' => sub { - $t->request( GET '/json' )->json_cmp( { message => 'Hello, World!' } ); + use Kelp::Base; + + sub random_number ($self, $id) + { + return { + id => $id, + randomNumber => int(rand(10_000) + 1), + }; + } + + sub fortune ($self) + { + return [ + { + id => 1, + message => 'フレームワークのベンチマーク', + }, + { + id => 2, + message => '', + }, + { + id => 3, + message => '&&/\\+?', + }, + ]; + } + + sub update ($self, $id, $random_number) + { + return; + } }; +my $app = KelpBench->new(mode => 'test', database => DBMock->new); +my $t = Kelp::Test->new(app => $app); +my $world = { randomNumber => re(qr{^\d+$}), id => re(qr{^\d+$}) }; + subtest plaintext => sub { - $t->request( GET '/plaintext' ) - ->content_type_is('text/plain') - ->content_is('Hello, World!'); + my $uri = '/plaintext'; + + $t->request(GET $uri) + ->content_type_is('text/plain') + ->content_is('Hello, World!'); +}; + +subtest 'json' => sub { + my $uri = '/json'; + + $t->request(GET $uri) + ->json_cmp({ message => 'Hello, World!' }); }; subtest db => sub { - for my $uri (qw{/db /db/mongo}) { - $t->request( GET $uri )->json_cmp($world); - } + my $uri = '/db'; + + $t->request(GET $uri) + ->json_cmp($world); }; subtest queries => sub { - for my $uri (qw{/queries /queries/mongo}) { - $t->request( GET $uri )->json_cmp($world); - $t->request( GET "$uri?queries=3" ) - ->json_cmp( [ $world, $world, $world ] ); - $t->request( GET "$uri?queries=0" )->json_cmp($world); - } + my $uri = '/queries'; + + $t->request(GET $uri) + ->json_cmp([$world]); + $t->request(GET "$uri?queries=3") + ->json_cmp([$world, $world, $world]); + $t->request(GET "$uri?queries=0") + ->json_cmp([$world]); }; subtest update => sub { - for my $uri (qw{/update /update/mongo}) { - $t->request( GET $uri )->json_cmp([$world]); - $t->request( GET "$uri?queries=3" ) - ->json_cmp( [ $world, $world, $world ] ); - } + my $uri = '/updates'; + + $t->request(GET $uri) + ->json_cmp([$world]); + $t->request(GET "$uri?queries=3") + ->json_cmp([ $world, $world, $world ]); }; subtest fortunes => sub { - for my $uri (qw{/fortunes /fortunes/mongo}) { - $t->request( GET $uri ) - ->content_type_is('text/html') - ->content_like(qr{<script>}) - ->content_like(qr{フレームワークのベンチマーク}) - ->content_like(qr{Additional fortune added at request time.}); - } + my $uri = '/fortunes'; + + $t->request(GET $uri) + ->content_type_is('text/html') + ->content_like(qr{<script>}) + ->content_like(qr{フレームワークのベンチマーク}) + ->content_like(qr{Additional fortune added at request time.}); }; done_testing; + diff --git a/frameworks/Perl/kelp/views/fortunes.tt b/frameworks/Perl/kelp/views/fortunes.tt new file mode 100644 index 00000000000..9667485892f --- /dev/null +++ b/frameworks/Perl/kelp/views/fortunes.tt @@ -0,0 +1,22 @@ + + + + Fortunes + + + + + + + + + %% FOREACH row IN rows + + + + + %% END +
idmessage
[% row.id %][% row.message | html %]
+ + + From 33500e87c5e5892a027203d90176e4906816d3c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BB=91=E5=B0=8F=E9=A9=AC?= <1417262058@qq.com> Date: Mon, 8 Jul 2024 23:28:23 +0800 Subject: [PATCH 018/204] Updating performance issues in the HServer framework. (#9119) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * hserver framework submit * hserver framework submit * lowercase fix * Required response header missing: Date fix * Date format fix * update hserver version * update hserver threadPool * update hserver * update hserver * update hserver query * update hserver query * Update README.md * update hserver query * update hserver query * update hserver query * update hserver query * update hserver query * update hserver query * Optimal configuration of hserver framework * Optimal configuration of hserver framework * Optimal configuration of hserver framework * Upgrade hserver Framework version and optimize configuration * Upgrade hserver Framework version and optimize configuration * Upgrade hserver Framework version and optimize configuration * Upgrade hserver Framework version and optimize configuration * Upgrade hserver Framework version and optimize configuration * Upgrade hserver Framework version and optimize configuration * Upgrade hserver Framework version and optimize configuration * Upgrade hserver Framework version and optimize configuration * Upgrade hserver Framework version and optimize configuration * Upgrade hserver Framework version and optimize configuration * Upgrade hserver Framework version and optimize configuration * Upgrade hserver Framework version and optimize configuration * Upgrade hserver Framework version and optimize configuration * Upgrade hserver Framework version and optimize configuration * Upgrade hserver Framework version and optimize configuration * Update pom.xml Upgrade dependencies, optimize performance. * Upgrade hserver Framework version and optimize configuration * Upgrade hserver Framework version and optimize configuration and Optimize log printing * Update pom.xml * Update StartApp.java --------- Co-authored-by: 黑小马 --- frameworks/Java/hserver/pom.xml | 2 +- .../Java/hserver/src/main/java/com/test/hserver/StartApp.java | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/frameworks/Java/hserver/pom.xml b/frameworks/Java/hserver/pom.xml index 4e304e8caf9..b841cbd60ab 100644 --- a/frameworks/Java/hserver/pom.xml +++ b/frameworks/Java/hserver/pom.xml @@ -11,7 +11,7 @@ hserver-parent cn.hserver - 3.4.M2 + 3.5.M2 UTF-8 diff --git a/frameworks/Java/hserver/src/main/java/com/test/hserver/StartApp.java b/frameworks/Java/hserver/src/main/java/com/test/hserver/StartApp.java index 87c5642d0b8..b4e215081da 100644 --- a/frameworks/Java/hserver/src/main/java/com/test/hserver/StartApp.java +++ b/frameworks/Java/hserver/src/main/java/com/test/hserver/StartApp.java @@ -13,8 +13,6 @@ public class StartApp { public static void main(String[] args) { - ConstConfig.bossPool = Runtime.getRuntime().availableProcessors()/2; - ConstConfig.workerPool = Runtime.getRuntime().availableProcessors(); HServerApplication.run(StartApp.class, 8888, args); } } From 9dffd6a7761897deb17ffb676e3500e4ac2ae4a3 Mon Sep 17 00:00:00 2001 From: Julien Viet Date: Mon, 8 Jul 2024 17:28:39 +0200 Subject: [PATCH 019/204] [java/vertx] Vert.x 4.5.8 bump + bunch of improvements (#9142) * Other contenders have clearly demonstrated that update benchmark performs better using a prepared statement with a aggregation of tuples instead of a postgres batch with a list of tuple. This change shamelessly borrows the SQL statement uwebsockets (thank you uwebsockets) with a small tweaks for the datatype. In other words UPDATE world SET randomNumber = update_data.randomNumber FROM (VALUES ($1::int,$2::int),...) AS update_data (id, randomNumber) WHERE world.id = update_data.id is superior (in this context) to a batch of UPDATE world SET randomnumber=$1 WHERE id=$2 * Use a single event-loop per CPU instead of the double. * Trim whitespace in rocker templates, shamelessly borrowed from Quarkus/Vertx benchmark. * Use a collecting query for fortunes that maps a row to a fortune instance which allocates a single row instance. This avoids allocating intermedary rows object when we map them to Fortune instances. Xerox tip: TFB Contenders using vertx-pg-client should copy this change to save some cycles. * Allocate a JsonArray of the right size for the query benchmark, avoid un-necessary string conversion in the generated JSON. * Avoid using Jackson databind that is actually not needed * Split reading/writing to the world table in two separate connections for the update benchmark, the hypothesis is that for the update benchmark first read then write to the World table, even though the write depends on the read, each change has a queue (the pipelined statements) and using two connections adds the operation to a queue with a smaller latency. This seems to give better results in my benchmark, let's see how this behaves out there. Xerox tip: TFB Contenders using vertx-pg-client should copy this change to save some cycles. * Bump Vert.x to 4.5.8 and its deps. --- frameworks/Java/vertx/pom.xml | 15 +- .../Java/vertx/src/main/java/vertx/App.java | 167 +++++++++++------- .../main/java/vertx/model/CachedWorld.java | 7 +- .../src/main/java/vertx/model/World.java | 7 +- .../src/main/java/vertx/model/WorldCache.java | 7 +- .../vertx/FortunesTemplate.rocker.html | 20 +-- 6 files changed, 132 insertions(+), 91 deletions(-) diff --git a/frameworks/Java/vertx/pom.xml b/frameworks/Java/vertx/pom.xml index 12ef914a5c5..cdb3aa09f6a 100644 --- a/frameworks/Java/vertx/pom.xml +++ b/frameworks/Java/vertx/pom.xml @@ -10,10 +10,10 @@ 17 vertx.App - 4.5.3 - 2.15.0 - 4.1.92.Final - 0.0.21.Final + 4.5.8 + 2.16.1 + 4.1.110.Final + 0.0.25.Final @@ -32,11 +32,6 @@ jackson-core ${jackson.version} - - com.fasterxml.jackson.core - jackson-databind - ${jackson.version} - io.netty netty-transport-native-kqueue @@ -91,7 +86,7 @@ 17 ${basedir}/src/main/templates ${basedir}/target/generated-sources/rocker - false + true true true true diff --git a/frameworks/Java/vertx/src/main/java/vertx/App.java b/frameworks/Java/vertx/src/main/java/vertx/App.java index 6d225d77d6c..5e81292d8ed 100755 --- a/frameworks/Java/vertx/src/main/java/vertx/App.java +++ b/frameworks/Java/vertx/src/main/java/vertx/App.java @@ -12,17 +12,11 @@ import io.vertx.core.http.HttpServerOptions; import io.vertx.core.http.HttpServerRequest; import io.vertx.core.http.HttpServerResponse; -import io.vertx.core.json.Json; import io.vertx.core.json.JsonArray; import io.vertx.core.json.JsonObject; import io.vertx.core.logging.Logger; import io.vertx.core.logging.LoggerFactory; -import io.vertx.sqlclient.PreparedQuery; -import io.vertx.sqlclient.PreparedStatement; -import io.vertx.sqlclient.Row; -import io.vertx.sqlclient.RowIterator; -import io.vertx.sqlclient.RowSet; -import io.vertx.sqlclient.Tuple; +import io.vertx.sqlclient.*; import io.vertx.sqlclient.impl.SqlClientInternal; import vertx.model.CachedWorld; import vertx.model.Fortune; @@ -41,7 +35,6 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; -import java.util.LinkedHashMap; import java.util.List; import java.util.concurrent.ThreadLocalRandom; import java.util.stream.Collectors; @@ -102,7 +95,8 @@ static int getQueries(HttpServerRequest request) { private static final String SELECT_WORLDS = "SELECT id, randomnumber from WORLD"; private HttpServer server; - private SqlClientInternal client; + private SqlClientInternal client1; + private SqlClientInternal client2; private CharSequence dateString; private CharSequence[] plaintextHeaders; @@ -110,8 +104,10 @@ static int getQueries(HttpServerRequest request) { private Throwable databaseErr; private PreparedQuery> SELECT_WORLD_QUERY; - private PreparedQuery> SELECT_FORTUNE_QUERY; + private PreparedQuery>> SELECT_FORTUNE_QUERY; private PreparedQuery> UPDATE_WORLD_QUERY; + @SuppressWarnings("unchecked") + private PreparedQuery>[] AGGREGATED_UPDATE_WORLD_QUERY = new PreparedQuery[128]; private WorldCache WORLD_CACHE; public static CharSequence createDateHeader() { @@ -139,28 +135,67 @@ public void start(Promise startPromise) throws Exception { options.setPassword(config.getString("password", "benchmarkdbpass")); options.setCachePreparedStatements(true); options.setPipeliningLimit(100_000); // Large pipelining means less flushing and we use a single connection anyway - PgConnection.connect(vertx, options) + Future clientsInit = initClients(options); + clientsInit + .transform(ar -> { + databaseErr = ar.cause(); + return server.listen(port); + }) + .mapEmpty() + .onComplete(startPromise); + } + + private Future initClients(PgConnectOptions options) { + Future cf1 = PgConnection.connect(vertx, options) .flatMap(conn -> { - client = (SqlClientInternal) conn; + client1 = (SqlClientInternal) conn; + List> list = new ArrayList<>(); Future f1 = conn.prepare(SELECT_WORLD) .andThen(onSuccess(ps -> SELECT_WORLD_QUERY = ps.query())); + list.add(f1); Future f2 = conn.prepare(SELECT_FORTUNE) - .andThen(onSuccess(ps -> SELECT_FORTUNE_QUERY = ps.query())); - Future f3 = conn.prepare(UPDATE_WORLD) - .andThen(onSuccess(ps -> UPDATE_WORLD_QUERY = ps.query())); - Future f4 = conn.preparedQuery(SELECT_WORLDS) + .andThen(onSuccess(ps -> { + SELECT_FORTUNE_QUERY = ps.query(). + collecting(Collectors.mapping(row -> new Fortune(row.getInteger(0), row.getString(1)), Collectors.toList())); + })); + list.add(f2); + Future f3 = conn.preparedQuery(SELECT_WORLDS) .collecting(Collectors.mapping(row -> new CachedWorld(row.getInteger(0), row.getInteger(1)), Collectors.toList())) .execute() .map(worlds -> new WorldCache(worlds.value())) .andThen(onSuccess(wc -> WORLD_CACHE = wc)); - return CompositeFuture.join(f1, f2, f3, f4); - }) - .transform(ar -> { - databaseErr = ar.cause(); - return server.listen(port); - }) - .mapEmpty() - .onComplete(startPromise); + list.add(f3); + return Future.join(list); + }); + Future cf2 = PgConnection.connect(vertx, options) + .flatMap(conn -> { + client2 = (SqlClientInternal) conn; + List> list = new ArrayList<>(); + Future f1 = conn.prepare(UPDATE_WORLD) + .andThen(onSuccess(ps -> UPDATE_WORLD_QUERY = ps.query())); + list.add(f1); + for (int i = 0; i < AGGREGATED_UPDATE_WORLD_QUERY.length; i++) { + int idx = i; + Future fut = conn + .prepare(buildAggregatedUpdateQuery(1 + idx)) + .andThen(onSuccess(ps -> AGGREGATED_UPDATE_WORLD_QUERY[idx] = ps.query())); + list.add(fut); + } + return Future.join(list); + }); + return Future.join(cf1, cf2); + } + + private static String buildAggregatedUpdateQuery(int len) { + StringBuilder sb = new StringBuilder(); + sb.append("UPDATE world SET randomNumber = update_data.randomNumber FROM (VALUES"); + char sep = ' '; + for (int i = 1;i <= len;i++) { + sb.append(sep).append("($").append(2 * i - 1).append("::int,$").append(2 * i).append("::int)"); + sep = ','; + } + sb.append(") AS update_data (id, randomNumber) WHERE world.id = update_data.id"); + return sb.toString(); } private static Handler> onSuccess(Handler handler) { @@ -259,7 +294,7 @@ private void handleDb(HttpServerRequest req) { .putHeader(HttpHeaders.SERVER, SERVER) .putHeader(HttpHeaders.DATE, dateString) .putHeader(HttpHeaders.CONTENT_TYPE, RESPONSE_TYPE_JSON) - .end(Json.encode(new World(row.getInteger(0), row.getInteger(1))), NULL_HANDLER); + .end(new World(row.getInteger(0), row.getInteger(1)).toBuffer(), NULL_HANDLER); } else { sendError(req, res.cause()); } @@ -269,19 +304,22 @@ private void handleDb(HttpServerRequest req) { class Queries implements Handler>> { boolean failed; - JsonArray worlds = new JsonArray(); + final JsonArray worlds; final HttpServerRequest req; final HttpServerResponse resp; final int queries; public Queries(HttpServerRequest req) { + int queries = getQueries(req); + this.req = req; this.resp = req.response(); - this.queries = getQueries(req); + this.queries = queries; + this.worlds = new JsonArray(new ArrayList<>(queries)); } private void handle() { - client.group(c -> { + client1.group(c -> { for (int i = 0; i < queries; i++) { c.preparedQuery(SELECT_WORLD).execute(Tuple.of(randomWorld()), this); } @@ -299,7 +337,7 @@ public void handle(AsyncResult> ar) { // we need a final reference final Tuple row = ar.result().iterator().next(); - worlds.add(new JsonObject().put("id", "" + row.getInteger(0)).put("randomNumber", "" + row.getInteger(1))); + worlds.add(new JsonObject().put("id", row.getInteger(0)).put("randomNumber", row.getInteger(1))); // stop condition if (worlds.size() == queries) { @@ -307,7 +345,7 @@ public void handle(AsyncResult> ar) { .putHeader(HttpHeaders.SERVER, SERVER) .putHeader(HttpHeaders.DATE, dateString) .putHeader(HttpHeaders.CONTENT_TYPE, RESPONSE_TYPE_JSON) - .end(worlds.encode(), NULL_HANDLER); + .end(worlds.toBuffer(), NULL_HANDLER); } } } @@ -328,7 +366,7 @@ public Update(HttpServerRequest req) { private void handle() { - client.group(c -> { + client1.group(c -> { PreparedQuery> preparedQuery = c.preparedQuery(SELECT_WORLD); for (int i = 0; i < worlds.length; i++) { int id = randomWorld(); @@ -352,42 +390,53 @@ private void handle() { void handleUpdates() { Arrays.sort(worlds); - List batch = new ArrayList<>(); - for (World world : worlds) { - batch.add(Tuple.of(world.getRandomNumber(), world.getId())); - } - UPDATE_WORLD_QUERY.executeBatch(batch, ar2 -> { - if (ar2.failed()) { - sendError(req, ar2.cause()); - return; + int len = worlds.length; + if (0 < len && len <= AGGREGATED_UPDATE_WORLD_QUERY.length) { + List arguments = new ArrayList<>(); + for (World world : worlds) { + arguments.add(world.getId()); + arguments.add(world.getRandomNumber()); } - JsonArray json = new JsonArray(); + Tuple tuple = Tuple.tuple(arguments); + PreparedQuery> query = AGGREGATED_UPDATE_WORLD_QUERY[len - 1]; + query.execute(tuple, this::sendResponse); + } else { + List batch = new ArrayList<>(); for (World world : worlds) { - json.add(new JsonObject().put("id", "" + world.getId()).put("randomNumber", "" + world.getRandomNumber())); + batch.add(Tuple.of(world.getRandomNumber(), world.getId())); } - req.response() - .putHeader(HttpHeaders.SERVER, SERVER) - .putHeader(HttpHeaders.DATE, dateString) - .putHeader(HttpHeaders.CONTENT_TYPE, RESPONSE_TYPE_JSON) - .end(json.toBuffer(), NULL_HANDLER); - }); + UPDATE_WORLD_QUERY.executeBatch(batch, this::sendResponse); + } } + + private void sendResponse(AsyncResult res) { + if (res.failed()) { + sendError(req, res.cause()); + return; + } + JsonArray json = new JsonArray(); + for (World world : worlds) { + json.add(world); + } + req.response() + .putHeader(HttpHeaders.SERVER, SERVER) + .putHeader(HttpHeaders.DATE, dateString) + .putHeader(HttpHeaders.CONTENT_TYPE, RESPONSE_TYPE_JSON) + .end(json.toBuffer(), NULL_HANDLER); + } + } private void handleFortunes(HttpServerRequest req) { SELECT_FORTUNE_QUERY.execute(ar -> { HttpServerResponse response = req.response(); if (ar.succeeded()) { - List fortunes = new ArrayList<>(); - RowIterator resultSet = ar.result().iterator(); - if (!resultSet.hasNext()) { + SqlResult> result = ar.result(); + if (result.size() == 0) { response.setStatusCode(404).end("No results"); return; } - while (resultSet.hasNext()) { - Row row = resultSet.next(); - fortunes.add(new Fortune(row.getInteger(0), row.getString(1))); - } + List fortunes = result.value(); fortunes.add(new Fortune(0, "Additional fortune added at request time.")); Collections.sort(fortunes); response @@ -412,12 +461,8 @@ private void handleCaching(HttpServerRequest req) { } count = Math.max(1, count); count = Math.min(500, count); - CachedWorld[] worlds = WORLD_CACHE.getCachedWorld(count); - JsonArray json = new JsonArray(new ArrayList<>(count)); - for (int i = 0;i < count;i++) { - CachedWorld world = worlds[i]; - json.add(JsonObject.of("id", world.getId(), "randomNumber", world.getRandomNumber())); - } + List worlds = WORLD_CACHE.getCachedWorld(count); + JsonArray json = new JsonArray(worlds); HttpServerResponse response = req.response(); MultiMap headers = response.headers(); headers @@ -429,7 +474,7 @@ private void handleCaching(HttpServerRequest req) { public static void main(String[] args) throws Exception { - int eventLoopPoolSize = VertxOptions.DEFAULT_EVENT_LOOP_POOL_SIZE; + int eventLoopPoolSize = Runtime.getRuntime().availableProcessors(); String sizeProp = System.getProperty("vertx.eventLoopPoolSize"); if (sizeProp != null) { try { diff --git a/frameworks/Java/vertx/src/main/java/vertx/model/CachedWorld.java b/frameworks/Java/vertx/src/main/java/vertx/model/CachedWorld.java index b369cc824da..f27e8805f33 100644 --- a/frameworks/Java/vertx/src/main/java/vertx/model/CachedWorld.java +++ b/frameworks/Java/vertx/src/main/java/vertx/model/CachedWorld.java @@ -1,9 +1,13 @@ package vertx.model; +import io.vertx.core.json.JsonObject; + +import java.util.Map; + /** * The model for the "world" database table. */ -public final class CachedWorld implements Comparable { +public final class CachedWorld extends JsonObject implements Comparable { private final int id; private final int randomNumber; @@ -15,6 +19,7 @@ public final class CachedWorld implements Comparable { * @param randomNumber the random number of the world */ public CachedWorld(int id, int randomNumber) { + super(Map.of("id", id, "randomNumber", randomNumber)); this.id = id; this.randomNumber = randomNumber; } diff --git a/frameworks/Java/vertx/src/main/java/vertx/model/World.java b/frameworks/Java/vertx/src/main/java/vertx/model/World.java index e733b265d65..86f4d29e99b 100644 --- a/frameworks/Java/vertx/src/main/java/vertx/model/World.java +++ b/frameworks/Java/vertx/src/main/java/vertx/model/World.java @@ -1,9 +1,13 @@ package vertx.model; +import io.vertx.core.json.JsonObject; + +import java.util.Map; + /** * The model for the "world" database table. */ -public final class World implements Comparable { +public final class World extends JsonObject implements Comparable { private final int id; private final int randomNumber; @@ -15,6 +19,7 @@ public final class World implements Comparable { * @param randomNumber the random number of the world */ public World(int id, int randomNumber) { + super(Map.of("id", id, "randomNumber", randomNumber)); this.id = id; this.randomNumber = randomNumber; } diff --git a/frameworks/Java/vertx/src/main/java/vertx/model/WorldCache.java b/frameworks/Java/vertx/src/main/java/vertx/model/WorldCache.java index c4d4b150283..2b0d4ae869c 100644 --- a/frameworks/Java/vertx/src/main/java/vertx/model/WorldCache.java +++ b/frameworks/Java/vertx/src/main/java/vertx/model/WorldCache.java @@ -3,6 +3,7 @@ import com.github.benmanes.caffeine.cache.Cache; import com.github.benmanes.caffeine.cache.Caffeine; +import java.util.ArrayList; import java.util.List; import java.util.concurrent.ThreadLocalRandom; @@ -19,12 +20,12 @@ public WorldCache(List worlds) { this.cache = cache; } - public CachedWorld[] getCachedWorld(int count) { - CachedWorld[] ret = new CachedWorld[count]; + public List getCachedWorld(int count) { + List ret = new ArrayList<>(count); ThreadLocalRandom current = ThreadLocalRandom.current(); for (int i = 0;i < count;i++) { Integer key = Integer.valueOf(current.nextInt(1000)); - ret[i] = cache.getIfPresent(key); + ret.add(cache.getIfPresent(key)); } return ret; } diff --git a/frameworks/Java/vertx/src/main/templates/vertx/FortunesTemplate.rocker.html b/frameworks/Java/vertx/src/main/templates/vertx/FortunesTemplate.rocker.html index 4a76266c344..8ceb4d68c7e 100644 --- a/frameworks/Java/vertx/src/main/templates/vertx/FortunesTemplate.rocker.html +++ b/frameworks/Java/vertx/src/main/templates/vertx/FortunesTemplate.rocker.html @@ -1,18 +1,8 @@ @import vertx.model.Fortune @import java.util.List @args(List fortunes) - - -Fortunes - - - - - - @for ((ForIterator i, Fortune fortune) : fortunes) { - - - - }
idmessage
@fortune.getId()@fortune.getMessage()
- - +Fortunes +@for ((ForIterator i, Fortune fortune) : fortunes) { + +} +
idmessage
@fortune.getId()@fortune.getMessage()
\ No newline at end of file From 82a228956c3aeebaa029b5464146330c0cab09c4 Mon Sep 17 00:00:00 2001 From: robert engels Date: Mon, 8 Jul 2024 10:29:46 -0500 Subject: [PATCH 020/204] optimized Java framework based on JDK supplied HTTP server (#9148) * dev environment * production * update README * update for latest httpserver --- frameworks/C++/libsniper/libs/core | 1 + frameworks/Java/httpserver-robaho/README.md | 32 ++++ .../httpserver-robaho/benchmark_config.json | 44 ++++++ frameworks/Java/httpserver-robaho/config.toml | 27 ++++ .../httpserver-robaho-postgres.dockerfile | 13 ++ .../httpserver-robaho.dockerfile | 13 ++ frameworks/Java/httpserver-robaho/pom.xml | 83 +++++++++++ .../src/main/java/benchmarks/Fortune.java | 25 ++++ .../src/main/java/benchmarks/Message.java | 26 ++++ .../src/main/java/benchmarks/Server.java | 139 ++++++++++++++++++ .../src/main/resources/fortunes.template.httl | 13 ++ 11 files changed, 416 insertions(+) create mode 160000 frameworks/C++/libsniper/libs/core create mode 100755 frameworks/Java/httpserver-robaho/README.md create mode 100755 frameworks/Java/httpserver-robaho/benchmark_config.json create mode 100644 frameworks/Java/httpserver-robaho/config.toml create mode 100644 frameworks/Java/httpserver-robaho/httpserver-robaho-postgres.dockerfile create mode 100644 frameworks/Java/httpserver-robaho/httpserver-robaho.dockerfile create mode 100644 frameworks/Java/httpserver-robaho/pom.xml create mode 100644 frameworks/Java/httpserver-robaho/src/main/java/benchmarks/Fortune.java create mode 100755 frameworks/Java/httpserver-robaho/src/main/java/benchmarks/Message.java create mode 100755 frameworks/Java/httpserver-robaho/src/main/java/benchmarks/Server.java create mode 100644 frameworks/Java/httpserver-robaho/src/main/resources/fortunes.template.httl diff --git a/frameworks/C++/libsniper/libs/core b/frameworks/C++/libsniper/libs/core new file mode 160000 index 00000000000..a792ecfebb0 --- /dev/null +++ b/frameworks/C++/libsniper/libs/core @@ -0,0 +1 @@ +Subproject commit a792ecfebb02f98bbdd8db232fba69f3f92907b3 diff --git a/frameworks/Java/httpserver-robaho/README.md b/frameworks/Java/httpserver-robaho/README.md new file mode 100755 index 00000000000..9317e30ce2d --- /dev/null +++ b/frameworks/Java/httpserver-robaho/README.md @@ -0,0 +1,32 @@ +# httpserver Benchmarking Test + +This is an alternative version of the [httpserver benchmarking test suite](../httpserver) + +Package [robaho.net.httpserver](https://github.com/robaho/httpserver) provides an implementation of `com.sun.net.httpserver` designed for virtual threads, thus requiring JDK21+. + +It can be used with platform threads using a `cached thread pool` which configures a thread per task, which is more efficient for a small number of clients (embedded systems). + +### Test Type Implementation Source Code + +* [JSON](src/main/java/benchmarks/Server.java) +* [Plaintext](src/main/java/benchmarks/Server.java) +* [Fortunes](src/main/java/benchmarks/Server.java) + +## Important Libraries +The tests were run with: +* [Jackson](https://github.com/FasterXML/jackson) +* [HikariCP](https://github.com/brettwooldridge/HikariCP) +* [HTTL](https://httl.github.io/en/) + +## Test URLs +### JSON + +http://localhost:8080/json + +### Plaintext + +http://localhost:8080/plaintext + +### Fortunes + +http://localhost:8080/fortunes diff --git a/frameworks/Java/httpserver-robaho/benchmark_config.json b/frameworks/Java/httpserver-robaho/benchmark_config.json new file mode 100755 index 00000000000..e3a66134723 --- /dev/null +++ b/frameworks/Java/httpserver-robaho/benchmark_config.json @@ -0,0 +1,44 @@ +{ + "framework": "httpserver-robaho", + "tests": [ + { + "default": { + "json_url": "/json", + "plaintext_url": "/plaintext", + "port": 8080, + "approach": "Realistic", + "classification": "Platform", + "database": "None", + "framework": "None", + "language": "Java", + "flavor": "None", + "orm": "Raw", + "platform": "httpserver", + "webserver": "None", + "os": "Linux", + "database_os": "Linux", + "display_name": "httpserver-robaho", + "notes": "", + "versus": "" + }, + "postgres": { + "fortune_url": "/fortunes", + "port": 8080, + "approach": "Realistic", + "classification": "Platform", + "database": "Postgres", + "framework": "None", + "language": "Java", + "flavor": "None", + "orm": "Raw", + "platform": "httpserver", + "webserver": "None", + "os": "Linux", + "database_os": "Linux", + "display_name": "httpserver-robaho-postgres", + "notes": "", + "versus": "" + } + } + ] +} diff --git a/frameworks/Java/httpserver-robaho/config.toml b/frameworks/Java/httpserver-robaho/config.toml new file mode 100644 index 00000000000..e69305d162c --- /dev/null +++ b/frameworks/Java/httpserver-robaho/config.toml @@ -0,0 +1,27 @@ +[framework] +name = "httpserver-robaho" + +[main] +urls.plaintext = "/plaintext" +urls.json = "/json" +approach = "Realistic" +classification = "Platform" +database = "None" +database_os = "Linux" +os = "Linux" +orm = "Raw" +platform = "httpserver" +webserver = "None" +versus = "" + +[postgres] +urls.fortune = "/fortunes" +approach = "Realistic" +classification = "Platform" +database = "Postgres" +database_os = "Linux" +os = "Linux" +orm = "Raw" +platform = "httpserver" +webserver = "None" +versus = "" diff --git a/frameworks/Java/httpserver-robaho/httpserver-robaho-postgres.dockerfile b/frameworks/Java/httpserver-robaho/httpserver-robaho-postgres.dockerfile new file mode 100644 index 00000000000..858df742cc8 --- /dev/null +++ b/frameworks/Java/httpserver-robaho/httpserver-robaho-postgres.dockerfile @@ -0,0 +1,13 @@ +FROM jelastic/maven:3.9.5-openjdk-21 as maven +WORKDIR /httpserver-robaho +COPY pom.xml pom.xml +COPY src src +RUN mvn compile assembly:single -q + +FROM openjdk:21-jdk-slim +WORKDIR /httpserver-robaho +COPY --from=maven /httpserver-robaho/target/httpserver-robaho-1.0-jar-with-dependencies.jar app.jar + +EXPOSE 8080 + +CMD ["java", "-server", "-jar", "app.jar", "postgres"] diff --git a/frameworks/Java/httpserver-robaho/httpserver-robaho.dockerfile b/frameworks/Java/httpserver-robaho/httpserver-robaho.dockerfile new file mode 100644 index 00000000000..d02bada7709 --- /dev/null +++ b/frameworks/Java/httpserver-robaho/httpserver-robaho.dockerfile @@ -0,0 +1,13 @@ +FROM jelastic/maven:3.9.5-openjdk-21 as maven +WORKDIR /httpserver-robaho +COPY pom.xml pom.xml +COPY src src +RUN mvn compile assembly:single -q + +FROM openjdk:21-jdk-slim +WORKDIR /httpserver-robaho +COPY --from=maven /httpserver-robaho/target/httpserver-robaho-1.0-jar-with-dependencies.jar app.jar + +EXPOSE 8080 + +CMD ["java", "-server", "-jar", "app.jar"] diff --git a/frameworks/Java/httpserver-robaho/pom.xml b/frameworks/Java/httpserver-robaho/pom.xml new file mode 100644 index 00000000000..ce9dc2cd27e --- /dev/null +++ b/frameworks/Java/httpserver-robaho/pom.xml @@ -0,0 +1,83 @@ + + 4.0.0 + com.techempower + httpserver-robaho + 1.0 + jar + + UTF-8 + 21 + 21 + 21 + + + + com.googlecode.json-simple + json-simple + 1.1.1 + + + org.postgresql + postgresql + 42.7.2 + + + com.zaxxer + HikariCP + 3.3.1 + + + com.github.httl + httl + 1.0.11 + + + org.slf4j + slf4j-simple + 1.7.25 + + + io.github.robaho + httpserver + 1.0.6 + compile + + + + + + true + org.apache.maven.plugins + maven-compiler-plugin + 3.8.0 + + false + + + + maven-assembly-plugin + 3.1.0 + + + + benchmarks.Server + + + + jar-with-dependencies + + + + + make-assembly + package + + single + + + + + + + diff --git a/frameworks/Java/httpserver-robaho/src/main/java/benchmarks/Fortune.java b/frameworks/Java/httpserver-robaho/src/main/java/benchmarks/Fortune.java new file mode 100644 index 00000000000..2b420fb4764 --- /dev/null +++ b/frameworks/Java/httpserver-robaho/src/main/java/benchmarks/Fortune.java @@ -0,0 +1,25 @@ +package benchmarks; + +public class Fortune implements Comparable { + + private final int id; + private final String message; + + public Fortune(int id, String message) { + this.id = id; + this.message = message; + } + + public int getId() { + return id; + } + + public String getMessage() { + return message; + } + + @Override + public int compareTo(Fortune other) { + return message.compareTo(other.message); + } +} diff --git a/frameworks/Java/httpserver-robaho/src/main/java/benchmarks/Message.java b/frameworks/Java/httpserver-robaho/src/main/java/benchmarks/Message.java new file mode 100755 index 00000000000..4c1ad6dc031 --- /dev/null +++ b/frameworks/Java/httpserver-robaho/src/main/java/benchmarks/Message.java @@ -0,0 +1,26 @@ +package benchmarks; + +import java.io.IOException; +import java.io.Writer; +import java.util.Map; + +import org.json.simple.JSONStreamAware; +import org.json.simple.JSONValue; + +public class Message implements JSONStreamAware { + + private final String message; + + public Message(String message) { + this.message = message; + } + + public String getMessage() { + return message; + } + + @Override + public void writeJSONString(Writer out) throws IOException { + JSONValue.writeJSONString(Map.of("message",message), out); + } +} diff --git a/frameworks/Java/httpserver-robaho/src/main/java/benchmarks/Server.java b/frameworks/Java/httpserver-robaho/src/main/java/benchmarks/Server.java new file mode 100755 index 00000000000..338200488d0 --- /dev/null +++ b/frameworks/Java/httpserver-robaho/src/main/java/benchmarks/Server.java @@ -0,0 +1,139 @@ +package benchmarks; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.OutputStreamWriter; +import java.net.InetSocketAddress; +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.text.ParseException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Properties; +import java.util.concurrent.Executors; + +import javax.sql.DataSource; + +import com.sun.net.httpserver.HttpHandler; +import com.sun.net.httpserver.HttpServer; +import com.zaxxer.hikari.HikariConfig; +import com.zaxxer.hikari.HikariDataSource; + +import httl.Engine; +import httl.Template; + +public class Server { + + private static final String HELLO_TEXT = "Hello, World!"; + private static final byte[] HELLO_BYTES = HELLO_TEXT.getBytes(); + private static final int HELLO_LENGTH = HELLO_BYTES.length; + private static final String SERVER_NAME = "httpserver-robaho"; + + private static List queryFortunes(DataSource ds) throws SQLException { + List fortunes = new ArrayList<>(); + try (Connection conn = ds.getConnection(); + PreparedStatement statement = conn.prepareStatement("SELECT id, message FROM fortune"); + ResultSet resultSet = statement.executeQuery()) { + while (resultSet.next()) + fortunes.add(new Fortune(resultSet.getInt(1), resultSet.getString(2))); + } + return fortunes; + } + + private static DataSource createPostgresDataSource() throws ClassNotFoundException { + Class.forName("org.postgresql.Driver"); + HikariConfig config = new HikariConfig(); + config.setJdbcUrl("jdbc:postgresql://tfb-database:5432/hello_world"); + config.setUsername("benchmarkdbuser"); + config.setPassword("benchmarkdbpass"); + config.setMaximumPoolSize(512); + return new HikariDataSource(config); + } + + private static Template loadTemplate(String filename) throws IOException, ParseException { + Properties props = new Properties(); + props.put("import.packages", "java.util," + Fortune.class.getPackage().getName()); + props.put("input.encoding", "UTF-8"); + props.put("output.encoding", "UTF-8"); + props.put("precompiled", "false"); + Engine engine = Engine.getEngine(props); + return engine.getTemplate(filename); + } + + private static HttpHandler createPlaintextHandler() { + return t -> { + t.getResponseHeaders().add("Content-Type", "text/plain"); + t.getResponseHeaders().add("Server", SERVER_NAME); + t.sendResponseHeaders(200, HELLO_LENGTH); + t.getResponseBody().write(HELLO_BYTES); + t.getResponseBody().close(); + }; + } + + private static HttpHandler createJSONHandler() { + return t -> { + Message m = new Message(HELLO_TEXT); + t.getResponseHeaders().add("Content-Type", "application/json"); + t.getResponseHeaders().add("Server", SERVER_NAME); + var bos = new ByteArrayOutputStream(); + OutputStreamWriter w = new OutputStreamWriter(bos); + m.writeJSONString(w); + w.flush(); + t.sendResponseHeaders(200, bos.size()); + bos.writeTo(t.getResponseBody()); + t.getResponseBody().close(); + }; + } + + private static HttpHandler createFortunesHandler(DataSource ds) throws IOException, ParseException { + Template template = loadTemplate("/fortunes.template.httl"); + return t -> { + try { + // query db + List fortunes = queryFortunes(ds); + fortunes.add(new Fortune(0, "Additional fortune added at request time.")); + Collections.sort(fortunes); + // render template + Map context = new HashMap<>(1); + context.put("fortunes", fortunes); + ByteArrayOutputStream out = new ByteArrayOutputStream(); + template.render(context, out); + byte[] bytes = out.toByteArray(); + // send response + t.getResponseHeaders().add("Content-Type", "text/html; charset=utf-8"); + t.getResponseHeaders().add("Server", SERVER_NAME); + t.sendResponseHeaders(200, bytes.length); + t.getResponseBody().write(bytes); + t.getResponseBody().close(); + } catch (SQLException | ParseException e) { + throw new IOException(e); + } + }; + } + + public static void main(String[] args) throws Exception { + // parse arguments + String settings = args.length > 0 ? args[0] : ""; + int port = args.length > 1 ? Integer.parseInt(args[1]) : 8080; + if (settings.contains("debug")) + System.setProperty("org.slf4j.simpleLogger.defaultLogLevel", "DEBUG"); + // create server + HttpServer server = HttpServer.create(new InetSocketAddress(port), 1024 * 8); + server.setExecutor(Executors.newVirtualThreadPerTaskExecutor()); + // server.setExecutor(Executors.newCachedThreadPool()); + // add context handlers + server.createContext("/plaintext", createPlaintextHandler()); + server.createContext("/json", createJSONHandler()); + if (settings.contains("postgres")) { + DataSource ds = createPostgresDataSource(); + server.createContext("/fortunes", createFortunesHandler(ds)); + } + // start server + server.start(); + } +} diff --git a/frameworks/Java/httpserver-robaho/src/main/resources/fortunes.template.httl b/frameworks/Java/httpserver-robaho/src/main/resources/fortunes.template.httl new file mode 100644 index 00000000000..4d87b47658a --- /dev/null +++ b/frameworks/Java/httpserver-robaho/src/main/resources/fortunes.template.httl @@ -0,0 +1,13 @@ + + + +Fortunes + + + + + + +
idmessage
${fortune.id}${fortune.message}
+ + From e9e401d678462395e1788a704e240d36279a0a08 Mon Sep 17 00:00:00 2001 From: uNetworkingAB <110806833+uNetworkingAB@users.noreply.github.com> Date: Mon, 8 Jul 2024 17:37:25 +0200 Subject: [PATCH 021/204] uWS.js is Platform (#9058) --- frameworks/JavaScript/uwebsockets.js/benchmark_config.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frameworks/JavaScript/uwebsockets.js/benchmark_config.json b/frameworks/JavaScript/uwebsockets.js/benchmark_config.json index c19862c849e..fee055f341a 100644 --- a/frameworks/JavaScript/uwebsockets.js/benchmark_config.json +++ b/frameworks/JavaScript/uwebsockets.js/benchmark_config.json @@ -4,7 +4,7 @@ { "default": { "approach": "Realistic", - "classification": "Micro", + "classification": "Platform", "database": "None", "database_os": "Linux", "display_name": "uWebSockets.js", From 8cad8194b9937da46411e3f7a67b18201cccd867 Mon Sep 17 00:00:00 2001 From: Petrik de Heus Date: Mon, 8 Jul 2024 17:40:29 +0200 Subject: [PATCH 022/204] [ruby] Use relative path to jemalloc (#9030) This makes sure it works on m1/m2 architecture as well. Linux is capable of resolving the path to the library. --- frameworks/Ruby/agoo/agoo.dockerfile | 2 +- frameworks/Ruby/grape/grape-unicorn.dockerfile | 5 +++++ frameworks/Ruby/grape/grape.dockerfile | 5 +++++ frameworks/Ruby/hanami/hanami.dockerfile | 2 +- .../Ruby/rack-sequel/rack-sequel-passenger-mri.dockerfile | 2 +- .../rack-sequel-postgres-passenger-mri.dockerfile | 2 +- .../rack-sequel-postgres-unicorn-mri.dockerfile | 2 +- .../Ruby/rack-sequel/rack-sequel-postgres.dockerfile | 2 +- .../Ruby/rack-sequel/rack-sequel-unicorn-mri.dockerfile | 2 +- frameworks/Ruby/rack-sequel/rack-sequel.dockerfile | 2 +- frameworks/Ruby/rack/rack-falcon.dockerfile | 2 +- frameworks/Ruby/rack/rack-unicorn.dockerfile | 2 +- frameworks/Ruby/rack/rack.dockerfile | 7 ++++++- frameworks/Ruby/rails/rails-mysql.dockerfile | 2 +- frameworks/Ruby/rails/rails.dockerfile | 2 +- .../Ruby/roda-sequel/roda-sequel-passenger-mri.dockerfile | 2 +- .../roda-sequel-postgres-passenger-mri.dockerfile | 2 +- .../roda-sequel-postgres-unicorn-mri.dockerfile | 2 +- .../Ruby/roda-sequel/roda-sequel-postgres.dockerfile | 2 +- .../Ruby/roda-sequel/roda-sequel-unicorn-mri.dockerfile | 2 +- frameworks/Ruby/roda-sequel/roda-sequel.dockerfile | 2 +- .../Ruby/sinatra-sequel/sinatra-sequel-base.dockerfile | 5 +++++ .../sinatra-sequel/sinatra-sequel-passenger-mri.dockerfile | 5 +++++ .../sinatra-sequel-postgres-passenger-mri.dockerfile | 5 +++++ .../sinatra-sequel-postgres-unicorn-mri.dockerfile | 5 +++++ .../Ruby/sinatra-sequel/sinatra-sequel-postgres.dockerfile | 5 +++++ .../sinatra-sequel/sinatra-sequel-unicorn-mri.dockerfile | 5 +++++ frameworks/Ruby/sinatra-sequel/sinatra-sequel.dockerfile | 5 +++++ frameworks/Ruby/sinatra/sinatra-passenger-mri.dockerfile | 2 +- .../Ruby/sinatra/sinatra-postgres-passenger-mri.dockerfile | 2 +- .../Ruby/sinatra/sinatra-postgres-unicorn-mri.dockerfile | 2 +- frameworks/Ruby/sinatra/sinatra-postgres.dockerfile | 2 +- frameworks/Ruby/sinatra/sinatra-unicorn-mri.dockerfile | 2 +- frameworks/Ruby/sinatra/sinatra.dockerfile | 2 +- 34 files changed, 75 insertions(+), 25 deletions(-) diff --git a/frameworks/Ruby/agoo/agoo.dockerfile b/frameworks/Ruby/agoo/agoo.dockerfile index bb4e363b687..c8c08141281 100644 --- a/frameworks/Ruby/agoo/agoo.dockerfile +++ b/frameworks/Ruby/agoo/agoo.dockerfile @@ -11,7 +11,7 @@ ENV RUBY_YJIT_ENABLE=1 # Use Jemalloc RUN apt-get update && \ apt-get install -y --no-install-recommends libjemalloc2 -ENV LD_PRELOAD=/usr/lib/x86_64-linux-gnu/libjemalloc.so.2 +ENV LD_PRELOAD=libjemalloc.so.2 WORKDIR /rack diff --git a/frameworks/Ruby/grape/grape-unicorn.dockerfile b/frameworks/Ruby/grape/grape-unicorn.dockerfile index 3cc4c7d2d37..f805021f71e 100644 --- a/frameworks/Ruby/grape/grape-unicorn.dockerfile +++ b/frameworks/Ruby/grape/grape-unicorn.dockerfile @@ -2,6 +2,11 @@ FROM ruby:3.3 ENV RUBY_YJIT_ENABLE=1 +# Use Jemalloc +RUN apt-get update && \ + apt-get install -y --no-install-recommends libjemalloc2 +ENV LD_PRELOAD=libjemalloc.so.2 + RUN apt-get update -yqq && apt-get install -yqq nginx ADD ./ /grape diff --git a/frameworks/Ruby/grape/grape.dockerfile b/frameworks/Ruby/grape/grape.dockerfile index 5beaf426ddd..99898d43e65 100644 --- a/frameworks/Ruby/grape/grape.dockerfile +++ b/frameworks/Ruby/grape/grape.dockerfile @@ -2,6 +2,11 @@ FROM ruby:3.3 ENV RUBY_YJIT_ENABLE=1 +# Use Jemalloc +RUN apt-get update && \ + apt-get install -y --no-install-recommends libjemalloc2 +ENV LD_PRELOAD=libjemalloc.so.2 + ADD ./ /grape WORKDIR /grape diff --git a/frameworks/Ruby/hanami/hanami.dockerfile b/frameworks/Ruby/hanami/hanami.dockerfile index 01972160167..6ba8e69f3e6 100644 --- a/frameworks/Ruby/hanami/hanami.dockerfile +++ b/frameworks/Ruby/hanami/hanami.dockerfile @@ -5,7 +5,7 @@ ENV RUBY_YJIT_ENABLE=1 # Use Jemalloc RUN apt-get update && \ apt-get install -y --no-install-recommends libjemalloc2 -ENV LD_PRELOAD=/usr/lib/x86_64-linux-gnu/libjemalloc.so.2 +ENV LD_PRELOAD=libjemalloc.so.2 WORKDIR /hanami diff --git a/frameworks/Ruby/rack-sequel/rack-sequel-passenger-mri.dockerfile b/frameworks/Ruby/rack-sequel/rack-sequel-passenger-mri.dockerfile index 7b82353185d..9482a004540 100644 --- a/frameworks/Ruby/rack-sequel/rack-sequel-passenger-mri.dockerfile +++ b/frameworks/Ruby/rack-sequel/rack-sequel-passenger-mri.dockerfile @@ -9,7 +9,7 @@ ENV RUBY_YJIT_ENABLE=1 # Use Jemalloc RUN apt-get update && \ apt-get install -y --no-install-recommends libjemalloc2 -ENV LD_PRELOAD=/usr/lib/x86_64-linux-gnu/libjemalloc.so.2 +ENV LD_PRELOAD=libjemalloc.so.2 RUN bundle install --jobs=4 --gemfile=/rack-sequel/Gemfile diff --git a/frameworks/Ruby/rack-sequel/rack-sequel-postgres-passenger-mri.dockerfile b/frameworks/Ruby/rack-sequel/rack-sequel-postgres-passenger-mri.dockerfile index 78053b6f376..2765c0c4f89 100644 --- a/frameworks/Ruby/rack-sequel/rack-sequel-postgres-passenger-mri.dockerfile +++ b/frameworks/Ruby/rack-sequel/rack-sequel-postgres-passenger-mri.dockerfile @@ -9,7 +9,7 @@ ENV RUBY_YJIT_ENABLE=1 # Use Jemalloc RUN apt-get update && \ apt-get install -y --no-install-recommends libjemalloc2 -ENV LD_PRELOAD=/usr/lib/x86_64-linux-gnu/libjemalloc.so.2 +ENV LD_PRELOAD=libjemalloc.so.2 RUN bundle install --jobs=4 --gemfile=/rack-sequel/Gemfile diff --git a/frameworks/Ruby/rack-sequel/rack-sequel-postgres-unicorn-mri.dockerfile b/frameworks/Ruby/rack-sequel/rack-sequel-postgres-unicorn-mri.dockerfile index a3aca7b79bc..37ce2662e7b 100644 --- a/frameworks/Ruby/rack-sequel/rack-sequel-postgres-unicorn-mri.dockerfile +++ b/frameworks/Ruby/rack-sequel/rack-sequel-postgres-unicorn-mri.dockerfile @@ -9,7 +9,7 @@ ENV RUBY_YJIT_ENABLE=1 # Use Jemalloc RUN apt-get update && \ apt-get install -y --no-install-recommends libjemalloc2 -ENV LD_PRELOAD=/usr/lib/x86_64-linux-gnu/libjemalloc.so.2 +ENV LD_PRELOAD=libjemalloc.so.2 RUN bundle install --jobs=4 --gemfile=/rack-sequel/Gemfile diff --git a/frameworks/Ruby/rack-sequel/rack-sequel-postgres.dockerfile b/frameworks/Ruby/rack-sequel/rack-sequel-postgres.dockerfile index 8033d74c31a..37634239c37 100644 --- a/frameworks/Ruby/rack-sequel/rack-sequel-postgres.dockerfile +++ b/frameworks/Ruby/rack-sequel/rack-sequel-postgres.dockerfile @@ -9,7 +9,7 @@ ENV RUBY_YJIT_ENABLE=1 # Use Jemalloc RUN apt-get update && \ apt-get install -y --no-install-recommends libjemalloc2 -ENV LD_PRELOAD=/usr/lib/x86_64-linux-gnu/libjemalloc.so.2 +ENV LD_PRELOAD=libjemalloc.so.2 RUN bundle install --jobs=4 --gemfile=/rack-sequel/Gemfile diff --git a/frameworks/Ruby/rack-sequel/rack-sequel-unicorn-mri.dockerfile b/frameworks/Ruby/rack-sequel/rack-sequel-unicorn-mri.dockerfile index 6df05c0c2b6..67ef3768e71 100644 --- a/frameworks/Ruby/rack-sequel/rack-sequel-unicorn-mri.dockerfile +++ b/frameworks/Ruby/rack-sequel/rack-sequel-unicorn-mri.dockerfile @@ -9,7 +9,7 @@ ENV RUBY_YJIT_ENABLE=1 # Use Jemalloc RUN apt-get update && \ apt-get install -y --no-install-recommends libjemalloc2 -ENV LD_PRELOAD=/usr/lib/x86_64-linux-gnu/libjemalloc.so.2 +ENV LD_PRELOAD=libjemalloc.so.2 RUN bundle install --jobs=4 --gemfile=/rack-sequel/Gemfile diff --git a/frameworks/Ruby/rack-sequel/rack-sequel.dockerfile b/frameworks/Ruby/rack-sequel/rack-sequel.dockerfile index 470d92aa4b3..2c7ee155a56 100644 --- a/frameworks/Ruby/rack-sequel/rack-sequel.dockerfile +++ b/frameworks/Ruby/rack-sequel/rack-sequel.dockerfile @@ -9,7 +9,7 @@ ENV RUBY_YJIT_ENABLE=1 # Use Jemalloc RUN apt-get update && \ apt-get install -y --no-install-recommends libjemalloc2 -ENV LD_PRELOAD=/usr/lib/x86_64-linux-gnu/libjemalloc.so.2 +ENV LD_PRELOAD=libjemalloc.so.2 RUN bundle install --jobs=4 --gemfile=/rack-sequel/Gemfile diff --git a/frameworks/Ruby/rack/rack-falcon.dockerfile b/frameworks/Ruby/rack/rack-falcon.dockerfile index ef5a63a10e7..f6ba1a106a2 100644 --- a/frameworks/Ruby/rack/rack-falcon.dockerfile +++ b/frameworks/Ruby/rack/rack-falcon.dockerfile @@ -5,7 +5,7 @@ ENV RUBY_YJIT_ENABLE=1 # Use Jemalloc RUN apt-get update && \ apt-get install -y --no-install-recommends libjemalloc2 -ENV LD_PRELOAD=/usr/lib/x86_64-linux-gnu/libjemalloc.so.2 +ENV LD_PRELOAD=libjemalloc.so.2 WORKDIR /rack diff --git a/frameworks/Ruby/rack/rack-unicorn.dockerfile b/frameworks/Ruby/rack/rack-unicorn.dockerfile index bc4807e5427..8609febfd7b 100644 --- a/frameworks/Ruby/rack/rack-unicorn.dockerfile +++ b/frameworks/Ruby/rack/rack-unicorn.dockerfile @@ -5,7 +5,7 @@ ENV RUBY_YJIT_ENABLE=1 # Use Jemalloc RUN apt-get update && \ apt-get install -y --no-install-recommends libjemalloc2 -ENV LD_PRELOAD=/usr/lib/x86_64-linux-gnu/libjemalloc.so.2 +ENV LD_PRELOAD=libjemalloc.so.2 WORKDIR /rack diff --git a/frameworks/Ruby/rack/rack.dockerfile b/frameworks/Ruby/rack/rack.dockerfile index 5b51b2ef1e0..e40bfced37a 100644 --- a/frameworks/Ruby/rack/rack.dockerfile +++ b/frameworks/Ruby/rack/rack.dockerfile @@ -1,12 +1,17 @@ FROM ruby:3.4-rc -ENV BUNDLE_FORCE_RUBY_PLATFORM=true ENV RUBY_YJIT_ENABLE=1 +# Use Jemalloc +RUN apt-get update && \ + apt-get install -y --no-install-recommends libjemalloc2 +ENV LD_PRELOAD=libjemalloc.so.2 + WORKDIR /rack COPY Gemfile ./ +ENV BUNDLE_FORCE_RUBY_PLATFORM=true RUN bundle config set without 'development test' RUN bundle install --jobs=8 diff --git a/frameworks/Ruby/rails/rails-mysql.dockerfile b/frameworks/Ruby/rails/rails-mysql.dockerfile index a93f26b52da..ae512cbdafd 100644 --- a/frameworks/Ruby/rails/rails-mysql.dockerfile +++ b/frameworks/Ruby/rails/rails-mysql.dockerfile @@ -10,7 +10,7 @@ ENV RUBY_YJIT_ENABLE=1 # Use Jemalloc RUN apt-get update && \ apt-get install -y --no-install-recommends libjemalloc2 -ENV LD_PRELOAD=/usr/lib/x86_64-linux-gnu/libjemalloc.so.2 +ENV LD_PRELOAD=libjemalloc.so.2 COPY ./Gemfile* /rails/ diff --git a/frameworks/Ruby/rails/rails.dockerfile b/frameworks/Ruby/rails/rails.dockerfile index 9d75f7d359e..99c16e935bb 100644 --- a/frameworks/Ruby/rails/rails.dockerfile +++ b/frameworks/Ruby/rails/rails.dockerfile @@ -9,7 +9,7 @@ ENV RUBY_YJIT_ENABLE=1 # Use Jemalloc RUN apt-get update && \ apt-get install -y --no-install-recommends libjemalloc2 -ENV LD_PRELOAD=/usr/lib/x86_64-linux-gnu/libjemalloc.so.2 +ENV LD_PRELOAD=libjemalloc.so.2 COPY ./Gemfile* /rails/ diff --git a/frameworks/Ruby/roda-sequel/roda-sequel-passenger-mri.dockerfile b/frameworks/Ruby/roda-sequel/roda-sequel-passenger-mri.dockerfile index 0af00a72d36..e25f21e20d9 100644 --- a/frameworks/Ruby/roda-sequel/roda-sequel-passenger-mri.dockerfile +++ b/frameworks/Ruby/roda-sequel/roda-sequel-passenger-mri.dockerfile @@ -8,7 +8,7 @@ ENV RUBY_YJIT_ENABLE=1 # Use Jemalloc RUN apt-get update && \ apt-get install -y --no-install-recommends libjemalloc2 -ENV LD_PRELOAD=/usr/lib/x86_64-linux-gnu/libjemalloc.so.2 +ENV LD_PRELOAD=libjemalloc.so.2 ENV BUNDLE_FORCE_RUBY_PLATFORM=true RUN bundle install --jobs=8 diff --git a/frameworks/Ruby/roda-sequel/roda-sequel-postgres-passenger-mri.dockerfile b/frameworks/Ruby/roda-sequel/roda-sequel-postgres-passenger-mri.dockerfile index a24b9881d00..b3f87e9c742 100644 --- a/frameworks/Ruby/roda-sequel/roda-sequel-postgres-passenger-mri.dockerfile +++ b/frameworks/Ruby/roda-sequel/roda-sequel-postgres-passenger-mri.dockerfile @@ -8,7 +8,7 @@ ENV RUBY_YJIT_ENABLE=1 # Use Jemalloc RUN apt-get update && \ apt-get install -y --no-install-recommends libjemalloc2 -ENV LD_PRELOAD=/usr/lib/x86_64-linux-gnu/libjemalloc.so.2 +ENV LD_PRELOAD=libjemalloc.so.2 ENV BUNDLE_FORCE_RUBY_PLATFORM=true RUN bundle install --jobs=8 diff --git a/frameworks/Ruby/roda-sequel/roda-sequel-postgres-unicorn-mri.dockerfile b/frameworks/Ruby/roda-sequel/roda-sequel-postgres-unicorn-mri.dockerfile index 3cde40eaa97..4865d5feebd 100644 --- a/frameworks/Ruby/roda-sequel/roda-sequel-postgres-unicorn-mri.dockerfile +++ b/frameworks/Ruby/roda-sequel/roda-sequel-postgres-unicorn-mri.dockerfile @@ -8,7 +8,7 @@ ENV RUBY_YJIT_ENABLE=1 # Use Jemalloc RUN apt-get update && \ apt-get install -y --no-install-recommends libjemalloc2 -ENV LD_PRELOAD=/usr/lib/x86_64-linux-gnu/libjemalloc.so.2 +ENV LD_PRELOAD=libjemalloc.so.2 ENV BUNDLE_FORCE_RUBY_PLATFORM=true RUN bundle install --jobs=8 diff --git a/frameworks/Ruby/roda-sequel/roda-sequel-postgres.dockerfile b/frameworks/Ruby/roda-sequel/roda-sequel-postgres.dockerfile index c74c9b9f0d3..d71a4b28a78 100644 --- a/frameworks/Ruby/roda-sequel/roda-sequel-postgres.dockerfile +++ b/frameworks/Ruby/roda-sequel/roda-sequel-postgres.dockerfile @@ -8,7 +8,7 @@ ENV RUBY_YJIT_ENABLE=1 # Use Jemalloc RUN apt-get update && \ apt-get install -y --no-install-recommends libjemalloc2 -ENV LD_PRELOAD=/usr/lib/x86_64-linux-gnu/libjemalloc.so.2 +ENV LD_PRELOAD=libjemalloc.so.2 ENV BUNDLE_FORCE_RUBY_PLATFORM=true RUN bundle install --jobs=8 diff --git a/frameworks/Ruby/roda-sequel/roda-sequel-unicorn-mri.dockerfile b/frameworks/Ruby/roda-sequel/roda-sequel-unicorn-mri.dockerfile index cda64c5c29b..d0cd81077bb 100644 --- a/frameworks/Ruby/roda-sequel/roda-sequel-unicorn-mri.dockerfile +++ b/frameworks/Ruby/roda-sequel/roda-sequel-unicorn-mri.dockerfile @@ -8,7 +8,7 @@ ENV RUBY_YJIT_ENABLE=1 # Use Jemalloc RUN apt-get update && \ apt-get install -y --no-install-recommends libjemalloc2 -ENV LD_PRELOAD=/usr/lib/x86_64-linux-gnu/libjemalloc.so.2 +ENV LD_PRELOAD=libjemalloc.so.2 ENV BUNDLE_FORCE_RUBY_PLATFORM=true RUN bundle install --jobs=8 diff --git a/frameworks/Ruby/roda-sequel/roda-sequel.dockerfile b/frameworks/Ruby/roda-sequel/roda-sequel.dockerfile index efa9d35597e..382f31291a1 100644 --- a/frameworks/Ruby/roda-sequel/roda-sequel.dockerfile +++ b/frameworks/Ruby/roda-sequel/roda-sequel.dockerfile @@ -8,7 +8,7 @@ ENV RUBY_YJIT_ENABLE=1 # Use Jemalloc RUN apt-get update && \ apt-get install -y --no-install-recommends libjemalloc2 -ENV LD_PRELOAD=/usr/lib/x86_64-linux-gnu/libjemalloc.so.2 +ENV LD_PRELOAD=libjemalloc.so.2 ENV BUNDLE_FORCE_RUBY_PLATFORM=true RUN bundle install --jobs=8 diff --git a/frameworks/Ruby/sinatra-sequel/sinatra-sequel-base.dockerfile b/frameworks/Ruby/sinatra-sequel/sinatra-sequel-base.dockerfile index 4fe264d4cb6..942d363b75c 100644 --- a/frameworks/Ruby/sinatra-sequel/sinatra-sequel-base.dockerfile +++ b/frameworks/Ruby/sinatra-sequel/sinatra-sequel-base.dockerfile @@ -2,6 +2,11 @@ FROM ruby:3.4-rc ENV RUBY_YJIT_ENABLE=1 +# Use Jemalloc +RUN apt-get update && \ + apt-get install -y --no-install-recommends libjemalloc2 +ENV LD_PRELOAD=libjemalloc.so.2 + ADD ./ /sinatra-sequel WORKDIR /sinatra-sequel diff --git a/frameworks/Ruby/sinatra-sequel/sinatra-sequel-passenger-mri.dockerfile b/frameworks/Ruby/sinatra-sequel/sinatra-sequel-passenger-mri.dockerfile index fe497718534..39bd11758da 100644 --- a/frameworks/Ruby/sinatra-sequel/sinatra-sequel-passenger-mri.dockerfile +++ b/frameworks/Ruby/sinatra-sequel/sinatra-sequel-passenger-mri.dockerfile @@ -2,6 +2,11 @@ FROM ruby:3.3 ENV RUBY_YJIT_ENABLE=1 +# Use Jemalloc +RUN apt-get update && \ + apt-get install -y --no-install-recommends libjemalloc2 +ENV LD_PRELOAD=libjemalloc.so.2 + ADD ./ /sinatra-sequel WORKDIR /sinatra-sequel diff --git a/frameworks/Ruby/sinatra-sequel/sinatra-sequel-postgres-passenger-mri.dockerfile b/frameworks/Ruby/sinatra-sequel/sinatra-sequel-postgres-passenger-mri.dockerfile index 74defc8326e..5651c491808 100644 --- a/frameworks/Ruby/sinatra-sequel/sinatra-sequel-postgres-passenger-mri.dockerfile +++ b/frameworks/Ruby/sinatra-sequel/sinatra-sequel-postgres-passenger-mri.dockerfile @@ -2,6 +2,11 @@ FROM ruby:3.3 ENV RUBY_YJIT_ENABLE=1 +# Use Jemalloc +RUN apt-get update && \ + apt-get install -y --no-install-recommends libjemalloc2 +ENV LD_PRELOAD=libjemalloc.so.2 + ADD ./ /sinatra-sequel WORKDIR /sinatra-sequel diff --git a/frameworks/Ruby/sinatra-sequel/sinatra-sequel-postgres-unicorn-mri.dockerfile b/frameworks/Ruby/sinatra-sequel/sinatra-sequel-postgres-unicorn-mri.dockerfile index 939eb97fce5..4d03257046a 100644 --- a/frameworks/Ruby/sinatra-sequel/sinatra-sequel-postgres-unicorn-mri.dockerfile +++ b/frameworks/Ruby/sinatra-sequel/sinatra-sequel-postgres-unicorn-mri.dockerfile @@ -2,6 +2,11 @@ FROM ruby:3.4-rc ENV RUBY_YJIT_ENABLE=1 +# Use Jemalloc +RUN apt-get update && \ + apt-get install -y --no-install-recommends libjemalloc2 +ENV LD_PRELOAD=libjemalloc.so.2 + ADD ./ /sinatra-sequel WORKDIR /sinatra-sequel diff --git a/frameworks/Ruby/sinatra-sequel/sinatra-sequel-postgres.dockerfile b/frameworks/Ruby/sinatra-sequel/sinatra-sequel-postgres.dockerfile index ab54544763d..77a2801d16d 100644 --- a/frameworks/Ruby/sinatra-sequel/sinatra-sequel-postgres.dockerfile +++ b/frameworks/Ruby/sinatra-sequel/sinatra-sequel-postgres.dockerfile @@ -2,6 +2,11 @@ FROM ruby:3.3 ENV RUBY_YJIT_ENABLE=1 +# Use Jemalloc +RUN apt-get update && \ + apt-get install -y --no-install-recommends libjemalloc2 +ENV LD_PRELOAD=libjemalloc.so.2 + ADD ./ /sinatra-sequel WORKDIR /sinatra-sequel diff --git a/frameworks/Ruby/sinatra-sequel/sinatra-sequel-unicorn-mri.dockerfile b/frameworks/Ruby/sinatra-sequel/sinatra-sequel-unicorn-mri.dockerfile index 78e45656c51..c3e2bc7de13 100644 --- a/frameworks/Ruby/sinatra-sequel/sinatra-sequel-unicorn-mri.dockerfile +++ b/frameworks/Ruby/sinatra-sequel/sinatra-sequel-unicorn-mri.dockerfile @@ -2,6 +2,11 @@ FROM ruby:3.4-rc ENV RUBY_YJIT_ENABLE=1 +# Use Jemalloc +RUN apt-get update && \ + apt-get install -y --no-install-recommends libjemalloc2 +ENV LD_PRELOAD=libjemalloc.so.2 + ADD ./ /sinatra-sequel WORKDIR /sinatra-sequel diff --git a/frameworks/Ruby/sinatra-sequel/sinatra-sequel.dockerfile b/frameworks/Ruby/sinatra-sequel/sinatra-sequel.dockerfile index e36c111221c..80198c299ab 100644 --- a/frameworks/Ruby/sinatra-sequel/sinatra-sequel.dockerfile +++ b/frameworks/Ruby/sinatra-sequel/sinatra-sequel.dockerfile @@ -2,6 +2,11 @@ FROM ruby:3.4-rc ENV RUBY_YJIT_ENABLE=1 +# Use Jemalloc +RUN apt-get update && \ + apt-get install -y --no-install-recommends libjemalloc2 +ENV LD_PRELOAD=libjemalloc.so.2 + ADD ./ /sinatra-sequel WORKDIR /sinatra-sequel diff --git a/frameworks/Ruby/sinatra/sinatra-passenger-mri.dockerfile b/frameworks/Ruby/sinatra/sinatra-passenger-mri.dockerfile index df0ddd1fa46..eb07d7b5ba7 100644 --- a/frameworks/Ruby/sinatra/sinatra-passenger-mri.dockerfile +++ b/frameworks/Ruby/sinatra/sinatra-passenger-mri.dockerfile @@ -5,7 +5,7 @@ ENV RUBY_YJIT_ENABLE=1 # Use Jemalloc RUN apt-get update && \ apt-get install -y --no-install-recommends libjemalloc2 -ENV LD_PRELOAD=/usr/lib/x86_64-linux-gnu/libjemalloc.so.2 +ENV LD_PRELOAD=libjemalloc.so.2 ADD ./ /sinatra WORKDIR /sinatra diff --git a/frameworks/Ruby/sinatra/sinatra-postgres-passenger-mri.dockerfile b/frameworks/Ruby/sinatra/sinatra-postgres-passenger-mri.dockerfile index 0ad6b16252b..2a09b22aeba 100644 --- a/frameworks/Ruby/sinatra/sinatra-postgres-passenger-mri.dockerfile +++ b/frameworks/Ruby/sinatra/sinatra-postgres-passenger-mri.dockerfile @@ -5,7 +5,7 @@ ENV RUBY_YJIT_ENABLE=1 # Use Jemalloc RUN apt-get update && \ apt-get install -y --no-install-recommends libjemalloc2 -ENV LD_PRELOAD=/usr/lib/x86_64-linux-gnu/libjemalloc.so.2 +ENV LD_PRELOAD=libjemalloc.so.2 ADD ./ /sinatra WORKDIR /sinatra diff --git a/frameworks/Ruby/sinatra/sinatra-postgres-unicorn-mri.dockerfile b/frameworks/Ruby/sinatra/sinatra-postgres-unicorn-mri.dockerfile index a38a0456218..027a5593040 100644 --- a/frameworks/Ruby/sinatra/sinatra-postgres-unicorn-mri.dockerfile +++ b/frameworks/Ruby/sinatra/sinatra-postgres-unicorn-mri.dockerfile @@ -5,7 +5,7 @@ ENV RUBY_YJIT_ENABLE=1 # Use Jemalloc RUN apt-get update && \ apt-get install -y --no-install-recommends libjemalloc2 -ENV LD_PRELOAD=/usr/lib/x86_64-linux-gnu/libjemalloc.so.2 +ENV LD_PRELOAD=libjemalloc.so.2 ADD ./ /sinatra WORKDIR /sinatra diff --git a/frameworks/Ruby/sinatra/sinatra-postgres.dockerfile b/frameworks/Ruby/sinatra/sinatra-postgres.dockerfile index 69ec07037dd..6258ac08c7d 100644 --- a/frameworks/Ruby/sinatra/sinatra-postgres.dockerfile +++ b/frameworks/Ruby/sinatra/sinatra-postgres.dockerfile @@ -5,7 +5,7 @@ ENV RUBY_YJIT_ENABLE=1 # Use Jemalloc RUN apt-get update && \ apt-get install -y --no-install-recommends libjemalloc2 -ENV LD_PRELOAD=/usr/lib/x86_64-linux-gnu/libjemalloc.so.2 +ENV LD_PRELOAD=libjemalloc.so.2 ADD ./ /sinatra WORKDIR /sinatra diff --git a/frameworks/Ruby/sinatra/sinatra-unicorn-mri.dockerfile b/frameworks/Ruby/sinatra/sinatra-unicorn-mri.dockerfile index 76ca52267f1..f0dede838aa 100644 --- a/frameworks/Ruby/sinatra/sinatra-unicorn-mri.dockerfile +++ b/frameworks/Ruby/sinatra/sinatra-unicorn-mri.dockerfile @@ -5,7 +5,7 @@ ENV RUBY_YJIT_ENABLE=1 # Use Jemalloc RUN apt-get update && \ apt-get install -y --no-install-recommends libjemalloc2 -ENV LD_PRELOAD=/usr/lib/x86_64-linux-gnu/libjemalloc.so.2 +ENV LD_PRELOAD=libjemalloc.so.2 ADD ./ /sinatra WORKDIR /sinatra diff --git a/frameworks/Ruby/sinatra/sinatra.dockerfile b/frameworks/Ruby/sinatra/sinatra.dockerfile index 85fe69e9b73..8e204def810 100644 --- a/frameworks/Ruby/sinatra/sinatra.dockerfile +++ b/frameworks/Ruby/sinatra/sinatra.dockerfile @@ -5,7 +5,7 @@ ENV RUBY_YJIT_ENABLE=1 # Use Jemalloc RUN apt-get update && \ apt-get install -y --no-install-recommends libjemalloc2 -ENV LD_PRELOAD=/usr/lib/x86_64-linux-gnu/libjemalloc.so.2 +ENV LD_PRELOAD=libjemalloc.so.2 ADD ./ /sinatra WORKDIR /sinatra From 158bd471ded84bb53c0b258601d32d7b4b4cd9fe Mon Sep 17 00:00:00 2001 From: Nathan Ortega Date: Mon, 8 Jul 2024 11:49:32 -0400 Subject: [PATCH 023/204] [New Framework]: Oxygen.jl (#8789) * added Oxygen.jl example with /plaintext and /json tests * renamed framework from oxygen-jl to oxygen * renamed top level directory to match framework name * updated readme --- frameworks/Julia/oxygen/README.md | 21 +++++++++++++++ frameworks/Julia/oxygen/benchmark_config.json | 26 +++++++++++++++++++ frameworks/Julia/oxygen/oxygen.dockerfile | 8 ++++++ frameworks/Julia/oxygen/src/Project.toml | 4 +++ frameworks/Julia/oxygen/src/server.jl | 23 ++++++++++++++++ 5 files changed, 82 insertions(+) create mode 100755 frameworks/Julia/oxygen/README.md create mode 100755 frameworks/Julia/oxygen/benchmark_config.json create mode 100644 frameworks/Julia/oxygen/oxygen.dockerfile create mode 100644 frameworks/Julia/oxygen/src/Project.toml create mode 100644 frameworks/Julia/oxygen/src/server.jl diff --git a/frameworks/Julia/oxygen/README.md b/frameworks/Julia/oxygen/README.md new file mode 100755 index 00000000000..5b7ac109195 --- /dev/null +++ b/frameworks/Julia/oxygen/README.md @@ -0,0 +1,21 @@ +# Oxygen.jl Benchmarking Test + +Oxygen is a micro-framework built on top of the HTTP.jl library and comes with helpful utilities to quickly setup and run web applications in Julia. + +### Test Type Implementation Source Code + +* [JSON](Relative/Path/To/Your/Source/File) +* [PLAINTEXT](Relative/Path/To/Your/Source/File) + +## Important Libraries +The tests were run with: +* [Oxygen.jl](https://github.com/OxygenFramework/Oxygen.jl) + +## Test URLs +### JSON + +http://localhost:8080/json + +### PLAINTEXT + +http://localhost:8080/plaintext diff --git a/frameworks/Julia/oxygen/benchmark_config.json b/frameworks/Julia/oxygen/benchmark_config.json new file mode 100755 index 00000000000..e998bb13773 --- /dev/null +++ b/frameworks/Julia/oxygen/benchmark_config.json @@ -0,0 +1,26 @@ +{ + "framework": "oxygen", + "tests": [ + { + "default": { + "json_url": "/json", + "plaintext_url": "/plaintext", + "port": 8080, + "approach": "Realistic", + "classification": "None", + "database": "None", + "framework": "Oxygen.jl", + "language": "Julia", + "orm": "None", + "platform": "None", + "webserver": "Oxygen.jl", + "os": "Linux", + "database_os": "Linux", + "display_name": "Oxygen.jl", + "notes": "", + "versus": "", + "tags": [] + } + } + ] +} \ No newline at end of file diff --git a/frameworks/Julia/oxygen/oxygen.dockerfile b/frameworks/Julia/oxygen/oxygen.dockerfile new file mode 100644 index 00000000000..df34f0a4b38 --- /dev/null +++ b/frameworks/Julia/oxygen/oxygen.dockerfile @@ -0,0 +1,8 @@ +FROM julia:latest + +WORKDIR /app +COPY ./src ./ +RUN julia --project -e 'using Pkg; Pkg.instantiate()' + +EXPOSE 8080 +CMD julia -t 2 --project server.jl \ No newline at end of file diff --git a/frameworks/Julia/oxygen/src/Project.toml b/frameworks/Julia/oxygen/src/Project.toml new file mode 100644 index 00000000000..dbe190679c2 --- /dev/null +++ b/frameworks/Julia/oxygen/src/Project.toml @@ -0,0 +1,4 @@ +[deps] +Dates = "ade2ca70-3891-5945-98fb-dc099432e06a" +HTTP = "cd3eb016-35fb-5094-929b-558a96fad6f3" +Oxygen = "df9a0d86-3283-4920-82dc-4555fc0d1d8b" diff --git a/frameworks/Julia/oxygen/src/server.jl b/frameworks/Julia/oxygen/src/server.jl new file mode 100644 index 00000000000..e88c1669472 --- /dev/null +++ b/frameworks/Julia/oxygen/src/server.jl @@ -0,0 +1,23 @@ + +using Oxygen +using Dates +using HTTP + +@get "/json" function() + return json(("message" => "Hello, World!")) +end + +@get "/plaintext" function() + return text("Hello, World!") +end + +function HeaderMiddleware(handle::Function) + function(req::HTTP.Request) + response = handle(req) + HTTP.setheader(response, "Server" => "Julia-Oxygen") + HTTP.setheader(response, "Date" => Dates.format(Dates.now(), Dates.RFC1123Format) * " GMT") + return response + end +end + +serveparallel(host="0.0.0.0", port=8080, middleware=[HeaderMiddleware], access_log=nothing, metrics=false, docs=false) \ No newline at end of file From 31ca740439ca9ebe3e80d72818421e0cffea647f Mon Sep 17 00:00:00 2001 From: Shagit Ziganshin <3687591+theLastOfCats@users.noreply.github.com> Date: Mon, 8 Jul 2024 19:28:30 +0300 Subject: [PATCH 024/204] [swift|vapor] Added Vapor+Swifql+Ikiga (#9146) * Added Vapor+Swifql+Ikiga (cherry picked from commit cf1fc17c508024927d35ca5da15aab1fa85d20ad) * Fixes so everything compiles * Another attempt at fixes * Removed unsupported @retroactive * Added db benchmark * FoundationEssentials JSON Coders support * Added everything else * Remove ikiga * remove FoundationPreview due to bug https://github.com/apple/swift-foundation/issues/715 * fix db hostname * fix fortune template * last fixes * fixed resources * hb2 compiles successfully * hb2-postgres compiles --------- Co-authored-by: Shagit Ziganshin Co-authored-by: Yakov Shapovalov --- .../Controllers/FortunesController.swift | 2 +- .../src-postgres/Sources/server/main.swift | 11 +- .../src/Sources/server/main.swift | 11 +- frameworks/Swift/vapor/benchmark_config.json | 23 ++++ frameworks/Swift/vapor/config.toml | 17 +++ .../Swift/vapor/vapor-swifql.dockerfile | 30 ++++ .../Swift/vapor/vapor-swifql/.dockerignore | 2 + .../Swift/vapor/vapor-swifql/.gitignore | 14 ++ .../Swift/vapor/vapor-swifql/Package.swift | 46 +++++++ .../vapor-swifql/Resources/Views/fortune.leaf | 10 ++ .../IkigaJSONCoders+ContentCoders.swift | 56 ++++++++ .../Sources/Extensions/Models+Content.swift | 11 ++ .../Sources/Extensions/Utils.swift | 18 +++ .../vapor-swifql/Sources/Models/Fortune.swift | 17 +++ .../vapor-swifql/Sources/Models/World.swift | 11 ++ .../vapor-swifql/Sources/configure.swift | 128 ++++++++++++++++++ .../vapor/vapor-swifql/Sources/main.swift | 16 +++ 17 files changed, 418 insertions(+), 5 deletions(-) create mode 100644 frameworks/Swift/vapor/vapor-swifql.dockerfile create mode 100644 frameworks/Swift/vapor/vapor-swifql/.dockerignore create mode 100644 frameworks/Swift/vapor/vapor-swifql/.gitignore create mode 100644 frameworks/Swift/vapor/vapor-swifql/Package.swift create mode 100644 frameworks/Swift/vapor/vapor-swifql/Resources/Views/fortune.leaf create mode 100644 frameworks/Swift/vapor/vapor-swifql/Sources/Extensions/IkigaJSONCoders+ContentCoders.swift create mode 100644 frameworks/Swift/vapor/vapor-swifql/Sources/Extensions/Models+Content.swift create mode 100644 frameworks/Swift/vapor/vapor-swifql/Sources/Extensions/Utils.swift create mode 100644 frameworks/Swift/vapor/vapor-swifql/Sources/Models/Fortune.swift create mode 100644 frameworks/Swift/vapor/vapor-swifql/Sources/Models/World.swift create mode 100644 frameworks/Swift/vapor/vapor-swifql/Sources/configure.swift create mode 100644 frameworks/Swift/vapor/vapor-swifql/Sources/main.swift diff --git a/frameworks/Swift/hummingbird2/src-postgres/Sources/server/Controllers/FortunesController.swift b/frameworks/Swift/hummingbird2/src-postgres/Sources/server/Controllers/FortunesController.swift index 159901dda40..cd8012c6d26 100644 --- a/frameworks/Swift/hummingbird2/src-postgres/Sources/server/Controllers/FortunesController.swift +++ b/frameworks/Swift/hummingbird2/src-postgres/Sources/server/Controllers/FortunesController.swift @@ -4,7 +4,7 @@ import PostgresNIO struct HTML: ResponseGenerator, Sendable { let html: String - public func response(from request: Request, context: some BaseRequestContext) -> Response { + public func response(from request: Request, context: some RequestContext) -> Response { let buffer = context.allocator.buffer(string: html) return Response(status: .ok, headers: [.contentType: "text/html; charset=utf-8"], body: .init(byteBuffer: buffer)) } diff --git a/frameworks/Swift/hummingbird2/src-postgres/Sources/server/main.swift b/frameworks/Swift/hummingbird2/src-postgres/Sources/server/main.swift index 65e360bfab3..772a52a5430 100644 --- a/frameworks/Swift/hummingbird2/src-postgres/Sources/server/main.swift +++ b/frameworks/Swift/hummingbird2/src-postgres/Sources/server/main.swift @@ -1,3 +1,4 @@ +import Foundation import Hummingbird import PostgresNIO @@ -15,15 +16,21 @@ struct TechFrameworkRequestContext: RequestContext { static let jsonEncoder = JSONEncoder() static let jsonDecoder = JSONDecoder() - var coreContext: Hummingbird.CoreRequestContext + var coreContext: Hummingbird.CoreRequestContextStorage // Use a global JSON Encoder var responseEncoder: JSONEncoder { Self.jsonEncoder } // Use a global JSON Decoder var requestDecoder: JSONDecoder { Self.jsonDecoder } + init(source: ApplicationRequestContextSource) { + self.init(channel: source.channel, logger: source.logger) + } + init(channel: any Channel, logger: Logger) { - self.coreContext = .init(allocator: channel.allocator, logger: logger) + self.coreContext = CoreRequestContextStorage( + source: ApplicationRequestContextSource(channel: channel, logger: logger) + ) } } diff --git a/frameworks/Swift/hummingbird2/src/Sources/server/main.swift b/frameworks/Swift/hummingbird2/src/Sources/server/main.swift index f652046a166..365b9a6a58f 100644 --- a/frameworks/Swift/hummingbird2/src/Sources/server/main.swift +++ b/frameworks/Swift/hummingbird2/src/Sources/server/main.swift @@ -1,4 +1,6 @@ +import Foundation import Hummingbird +import HummingbirdCore import Logging import NIOCore @@ -7,18 +9,23 @@ struct Object: ResponseEncodable { } struct TechFrameworkRequestContext: RequestContext { + static let jsonEncoder = JSONEncoder() static let jsonDecoder = JSONDecoder() - var coreContext: Hummingbird.CoreRequestContext + var coreContext: Hummingbird.CoreRequestContextStorage // Use a global JSON Encoder var responseEncoder: JSONEncoder { Self.jsonEncoder } // Use a global JSON Decoder var requestDecoder: JSONDecoder { Self.jsonDecoder } + init(source: Hummingbird.ApplicationRequestContextSource) { + self.coreContext = CoreRequestContextStorage(source: ApplicationRequestContextSource(channel: source.channel, logger: source.logger)) + } + init(channel: any Channel, logger: Logger) { - self.coreContext = .init(allocator: channel.allocator, logger: logger) + self.coreContext = CoreRequestContextStorage(source: ApplicationRequestContextSource(channel: channel, logger: logger)) } } diff --git a/frameworks/Swift/vapor/benchmark_config.json b/frameworks/Swift/vapor/benchmark_config.json index 1bd0d8e2242..00b6bb943dc 100755 --- a/frameworks/Swift/vapor/benchmark_config.json +++ b/frameworks/Swift/vapor/benchmark_config.json @@ -93,6 +93,29 @@ "display_name": "Vapor", "notes": "", "versus": "None" + }, + "swifql": { + "plaintext_url": "/plaintext", + "json_url": "/json", + "db_url": "/db", + "query_url": "/queries?queries=", + "update_url": "/updates?queries=", + "fortune_url": "/fortunes", + "database": "Postgres", + "orm": "Micro", + "port": 8080, + "approach": "Realistic", + "classification": "Fullstack", + "framework": "Vapor", + "language": "Swift", + "flavor": "None", + "platform": "None", + "webserver": "None", + "os": "Linux", + "database_os": "Linux", + "display_name": "Vapor", + "notes": "", + "versus": "None" } }] } diff --git a/frameworks/Swift/vapor/config.toml b/frameworks/Swift/vapor/config.toml index e629702ef66..24db8e89c90 100644 --- a/frameworks/Swift/vapor/config.toml +++ b/frameworks/Swift/vapor/config.toml @@ -51,3 +51,20 @@ orm = "Micro" platform = "None" webserver = "None" versus = "None" + +[swifql] +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 = "Micro" +platform = "None" +webserver = "None" +versus = "None" \ No newline at end of file diff --git a/frameworks/Swift/vapor/vapor-swifql.dockerfile b/frameworks/Swift/vapor/vapor-swifql.dockerfile new file mode 100644 index 00000000000..d39373d63a6 --- /dev/null +++ b/frameworks/Swift/vapor/vapor-swifql.dockerfile @@ -0,0 +1,30 @@ +# ================================ +# Build image +# ================================ +FROM swift:5.10 as build +WORKDIR /build + +# Copy entire repo into container +COPY ./vapor-swifql . + +# Compile with optimizations +RUN swift build \ + -c release \ + -Xswiftc -enforce-exclusivity=unchecked + +# ================================ +# Run image +# ================================ +FROM swift:5.10-slim +WORKDIR /run + +# Copy build artifacts +COPY --from=build /build/.build/release /run +COPY ./vapor-swifql/Resources/Views/fortune.leaf /run/Resources/Views/fortune.leaf + +# Copy Swift runtime libraries +COPY --from=build /usr/lib/swift/ /usr/lib/swift/ + +EXPOSE 8080 + +ENTRYPOINT ["./app", "serve", "--env", "production", "--hostname", "0.0.0.0", "--port", "8080"] diff --git a/frameworks/Swift/vapor/vapor-swifql/.dockerignore b/frameworks/Swift/vapor/vapor-swifql/.dockerignore new file mode 100644 index 00000000000..2d9f16e2d27 --- /dev/null +++ b/frameworks/Swift/vapor/vapor-swifql/.dockerignore @@ -0,0 +1,2 @@ +.build/ +.swiftpm/ diff --git a/frameworks/Swift/vapor/vapor-swifql/.gitignore b/frameworks/Swift/vapor/vapor-swifql/.gitignore new file mode 100644 index 00000000000..1f4d514fd4c --- /dev/null +++ b/frameworks/Swift/vapor/vapor-swifql/.gitignore @@ -0,0 +1,14 @@ +Packages +.build +xcuserdata +*.xcodeproj +DerivedData/ +.DS_Store +db.sqlite +.swiftpm +.env +.env.* +! .env.example +.vscode +docker-compose.yml +Dockerfile \ No newline at end of file diff --git a/frameworks/Swift/vapor/vapor-swifql/Package.swift b/frameworks/Swift/vapor/vapor-swifql/Package.swift new file mode 100644 index 00000000000..43d9104cecd --- /dev/null +++ b/frameworks/Swift/vapor/vapor-swifql/Package.swift @@ -0,0 +1,46 @@ +// swift-tools-version:5.10 + +import PackageDescription + +let package = Package( + name: "vapor-swifql-ikiga", + platforms: [ + .macOS(.v12) + ], + products: [ + .executable(name: "app", targets: ["App"]) + ], + dependencies: [ + // 💧 A server-side Swift web framework. + .package(url: "https://github.com/vapor/vapor.git", from: "4.99.3"), + .package(url: "https://github.com/vapor/leaf.git", from: "4.0.0"), + // 🔵 Non-blocking, event-driven networking for Swift. Used for custom executors + .package(url: "https://github.com/apple/swift-nio.git", from: "2.65.0"), + // json encoder/decoder + .package(url: "https://github.com/orlandos-nl/IkigaJSON.git", from: "2.0.0"), + // sql builder + .package(url: "https://github.com/SwifQL/VaporBridges.git", from: "1.0.0-rc"), + .package(url: "https://github.com/SwifQL/PostgresBridge.git", from: "1.0.0-rc"), + ], + targets: [ + .executableTarget( + name: "App", + dependencies: [ + .product(name: "Vapor", package: "vapor"), + .product(name: "Leaf", package: "leaf"), + .product(name: "NIOCore", package: "swift-nio"), + .product(name: "NIOPosix", package: "swift-nio"), + .product(name: "VaporBridges", package: "VaporBridges"), + .product(name: "PostgresBridge", package: "PostgresBridge"), + .product(name: "IkigaJSON", package: "IkigaJSON"), + ], + swiftSettings: swiftSettings + ) + ] +) + +var swiftSettings: [SwiftSetting] { [ + .enableUpcomingFeature("DisableOutwardActorInference"), + .enableExperimentalFeature("StrictConcurrency"), + .unsafeFlags(["-parse-as-library"]), +] } diff --git a/frameworks/Swift/vapor/vapor-swifql/Resources/Views/fortune.leaf b/frameworks/Swift/vapor/vapor-swifql/Resources/Views/fortune.leaf new file mode 100644 index 00000000000..020d76adc92 --- /dev/null +++ b/frameworks/Swift/vapor/vapor-swifql/Resources/Views/fortune.leaf @@ -0,0 +1,10 @@ + + +Fortunes + + + +#for(fortune in fortunes): +#endfor
idmessage
#(fortune.id)#(fortune.message)
+ + \ No newline at end of file diff --git a/frameworks/Swift/vapor/vapor-swifql/Sources/Extensions/IkigaJSONCoders+ContentCoders.swift b/frameworks/Swift/vapor/vapor-swifql/Sources/Extensions/IkigaJSONCoders+ContentCoders.swift new file mode 100644 index 00000000000..676ff7285b6 --- /dev/null +++ b/frameworks/Swift/vapor/vapor-swifql/Sources/Extensions/IkigaJSONCoders+ContentCoders.swift @@ -0,0 +1,56 @@ +// +// IkigaJSONCoders+ContentCoders.swift +// +// +// Created by Yakov Shapovalov on 04.07.2024. +// + +import IkigaJSON +import Vapor + +extension IkigaJSONEncoder: ContentEncoder { + public func encode( + _ encodable: E, + to body: inout ByteBuffer, + headers: inout HTTPHeaders + ) throws { + headers.contentType = .json + try self.encodeAndWrite(encodable, into: &body) + } + + public func encode(_ encodable: E, to body: inout ByteBuffer, headers: inout HTTPHeaders, userInfo: [CodingUserInfoKey : Sendable]) throws where E : Encodable { + var encoder = self + encoder.userInfo = userInfo + headers.contentType = .json + try encoder.encodeAndWrite(encodable, into: &body) + } + + public func encode(_ encodable: E, to body: inout ByteBuffer, headers: inout HTTPHeaders, userInfo: [CodingUserInfoKey : Any]) throws where E : Encodable { + var encoder = self + encoder.userInfo = userInfo + headers.contentType = .json + try encoder.encodeAndWrite(encodable, into: &body) + } +} + +extension IkigaJSONDecoder: ContentDecoder { + public func decode( + _ decodable: D.Type, + from body: ByteBuffer, + headers: HTTPHeaders + ) throws -> D { + return try self.decode(D.self, from: body) + } + + public func decode(_ decodable: D.Type, from body: ByteBuffer, headers: HTTPHeaders, userInfo: [CodingUserInfoKey : Sendable]) throws -> D where D : Decodable { + let decoder = IkigaJSONDecoder(settings: settings) + decoder.settings.userInfo = userInfo + return try decoder.decode(D.self, from: body) + } + + public func decode(_ decodable: D.Type, from body: ByteBuffer, headers: HTTPHeaders, userInfo: [CodingUserInfoKey : Any]) throws -> D where D : Decodable { + let decoder = IkigaJSONDecoder(settings: settings) + decoder.settings.userInfo = userInfo + return try decoder.decode(D.self, from: body) + } +} diff --git a/frameworks/Swift/vapor/vapor-swifql/Sources/Extensions/Models+Content.swift b/frameworks/Swift/vapor/vapor-swifql/Sources/Extensions/Models+Content.swift new file mode 100644 index 00000000000..8fdae4b378f --- /dev/null +++ b/frameworks/Swift/vapor/vapor-swifql/Sources/Extensions/Models+Content.swift @@ -0,0 +1,11 @@ +// +// Models+Content.swift +// +// +// Created by Yakov Shapovalov on 04.07.2024. +// + +import Vapor + +extension World: Content {} +extension Fortune: Content {} diff --git a/frameworks/Swift/vapor/vapor-swifql/Sources/Extensions/Utils.swift b/frameworks/Swift/vapor/vapor-swifql/Sources/Extensions/Utils.swift new file mode 100644 index 00000000000..d370b15e291 --- /dev/null +++ b/frameworks/Swift/vapor/vapor-swifql/Sources/Extensions/Utils.swift @@ -0,0 +1,18 @@ +extension Int { + func bounded(to range: ClosedRange) -> Int { + switch self { + case ...range.lowerBound: + return range.lowerBound + case range.upperBound...: + return range.upperBound + default: + return self + } + } +} + +extension Int: Sequence { + public func makeIterator() -> CountableRange.Iterator { + return (0.. World in + guard let world: World = try await req.postgres.connection(to: .Db, { conn in + World.select + .where(\World.$id == Int.random(in: 1...10_000)) + .execute(on: conn) + .first(decoding: World.self) + }).get() else { + throw Abort(.notFound) + } + return world + } + + app.get("queries") { req async throws -> [World] in + let queries: Int = (req.query["queries"] ?? 1).bounded(to: 1...500) + + var worlds: [World] = [] + + for _ in queries { + guard let world: World = try await req.postgres.connection(to: .Db, { conn in + World.select + .where(\World.$id == Int.random(in: 1...10_000)) + .execute(on: conn) + .first(decoding: World.self) + }).get() else { + throw Abort(.notFound) + } + + worlds.append(world) + } + return worlds + } + + app.get("updates") { req async throws -> [World] in + let queries = (req.query["queries"] ?? 1).bounded(to: 1...500) + + var worlds: [World] = [] + + for _ in queries { + let world = try await req.postgres.connection(to: .Db, { conn in + World.select.where(\World.$id == Int.random(in: 1...10_000)).execute(on: conn).first(decoding: World.self).flatMap { world in + world!.randomnumber = .random(in: 1...10_000) + return world!.update(on: \.$id, on: conn) + } + }).get() + + worlds.append(world) + } + + return worlds + + } + + app.get("fortunes") { req async throws -> View in + var fortunes: [Fortune] = try await req.postgres.connection(to: .Db, {conn in + Fortune.select.execute(on: conn).all(decoding: Fortune.self) + }) + .get() + + fortunes.append(Fortune(id: 0, message: "Additional fortune added at request time.")) + + fortunes.sort(by: { + $0.message < $1.message + }) + + return try await req.view.render("fortune", ["fortunes": fortunes]) + } +} + diff --git a/frameworks/Swift/vapor/vapor-swifql/Sources/main.swift b/frameworks/Swift/vapor/vapor-swifql/Sources/main.swift new file mode 100644 index 00000000000..81feddfbc02 --- /dev/null +++ b/frameworks/Swift/vapor/vapor-swifql/Sources/main.swift @@ -0,0 +1,16 @@ +import Vapor +import PostgresBridge +import Logging + +@main +enum App { + static func main() throws { + var env = try Environment.detect() + try LoggingSystem.bootstrap(from: &env) + + let app = Application(env) + defer { app.shutdown() } + + try configure(app) + } +} From 3a6fcdbbb38025e59c16e5a92b1b4e3c49647413 Mon Sep 17 00:00:00 2001 From: uNetworkingAB <110806833+uNetworkingAB@users.noreply.github.com> Date: Mon, 8 Jul 2024 19:33:49 +0200 Subject: [PATCH 025/204] [uwebsockets.js] Use faster plaintext response, update version (#9056) --- frameworks/JavaScript/uwebsockets.js/package-lock.json | 6 +++--- frameworks/JavaScript/uwebsockets.js/package.json | 2 +- frameworks/JavaScript/uwebsockets.js/src/server.js | 10 +++++----- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/frameworks/JavaScript/uwebsockets.js/package-lock.json b/frameworks/JavaScript/uwebsockets.js/package-lock.json index 275f2f63b2e..910703e95b8 100644 --- a/frameworks/JavaScript/uwebsockets.js/package-lock.json +++ b/frameworks/JavaScript/uwebsockets.js/package-lock.json @@ -12,7 +12,7 @@ "mariadb": "^3.3.0", "postgres": "^3.4.4", "slow-json-stringify": "^2.0.1", - "uWebSockets.js": "uNetworking/uWebSockets.js#v20.43.0" + "uWebSockets.js": "uNetworking/uWebSockets.js#v20.44.0" } }, "node_modules/@types/geojson": { @@ -98,8 +98,8 @@ "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==" }, "node_modules/uWebSockets.js": { - "version": "20.31.0", - "resolved": "git+ssh://git@github.com/uNetworking/uWebSockets.js.git#809b99d2d7d12e2cbf89b7135041e9b41ff84084" + "version": "20.44.0", + "resolved": "git+ssh://git@github.com/uNetworking/uWebSockets.js.git#8fa05571bf6ea95be8966ad313d9d39453e381ae" } } } diff --git a/frameworks/JavaScript/uwebsockets.js/package.json b/frameworks/JavaScript/uwebsockets.js/package.json index c64742e442d..ec5bc0c1d73 100644 --- a/frameworks/JavaScript/uwebsockets.js/package.json +++ b/frameworks/JavaScript/uwebsockets.js/package.json @@ -3,7 +3,7 @@ "mariadb": "^3.3.0", "postgres": "^3.4.4", "slow-json-stringify": "^2.0.1", - "uWebSockets.js": "uNetworking/uWebSockets.js#v20.43.0" + "uWebSockets.js": "uNetworking/uWebSockets.js#v20.44.0" }, "license": "MIT", "main": "src/server.js", diff --git a/frameworks/JavaScript/uwebsockets.js/src/server.js b/frameworks/JavaScript/uwebsockets.js/src/server.js index f67f33e874b..1db7d391f2a 100644 --- a/frameworks/JavaScript/uwebsockets.js/src/server.js +++ b/frameworks/JavaScript/uwebsockets.js/src/server.js @@ -16,11 +16,11 @@ if (DATABASE) db = await import(`./database/${DATABASE}.js`); const webserver = uWebSockets.App(); -webserver.get("/plaintext", (response) => { - addBenchmarkHeaders(response); - response.writeHeader("Content-Type", "text/plain"); - response.end("Hello, World!"); -}); +webserver.get("/plaintext", new uWebSockets.DeclarativeResponse() + .writeHeader("Server", "uWebSockets.js") + .writeHeader("Content-Type", "text/plain") + .end("Hello, World!") +); webserver.get("/json", (response) => { addBenchmarkHeaders(response); From 63f467e295b3f722dd850d2e064a1211447e3580 Mon Sep 17 00:00:00 2001 From: Bartosz Jarzyna <44323413+bbrtj@users.noreply.github.com> Date: Tue, 9 Jul 2024 20:01:54 +0200 Subject: [PATCH 026/204] Perl: Fix non-functional benchmarks (#9151) * Perl: unify the maximum requests per child value * Fix Perl Dancer * Fix Perl Web::Simple * Fix Perl Plack * Fix Perl Mojolicious * Perl Kelp: provide a default benchmark to silence the warning * Perl Mojolicious: minor adjustments --- frameworks/Perl/dancer/README.md | 3 +- frameworks/Perl/dancer/app.pl | 7 +- frameworks/Perl/dancer/benchmark_config.json | 3 +- frameworks/Perl/dancer/dancer.dockerfile | 7 +- frameworks/Perl/kelp/benchmark_config.json | 2 +- frameworks/Perl/kelp/run.pl | 4 + frameworks/Perl/mojolicious/app.pl | 116 +++---- frameworks/Perl/mojolicious/cpanfile | 3 +- frameworks/Perl/mojolicious/cpanfile.snapshot | 319 +++++++++--------- .../Perl/mojolicious/mojolicious.dockerfile | 3 +- frameworks/Perl/plack/README.md | 3 +- frameworks/Perl/plack/app-async.psgi | 3 +- frameworks/Perl/plack/app.pl | 4 +- frameworks/Perl/plack/app.psgi | 5 +- frameworks/Perl/plack/plack-async.dockerfile | 3 +- frameworks/Perl/plack/plack.dockerfile | 3 +- frameworks/Perl/web-simple/README.md | 3 +- frameworks/Perl/web-simple/app.pl | 3 +- .../Perl/web-simple/benchmark_config.json | 3 +- .../Perl/web-simple/web-simple.dockerfile | 6 +- 20 files changed, 256 insertions(+), 247 deletions(-) diff --git a/frameworks/Perl/dancer/README.md b/frameworks/Perl/dancer/README.md index c2afcf7639c..56b1d27d773 100644 --- a/frameworks/Perl/dancer/README.md +++ b/frameworks/Perl/dancer/README.md @@ -8,7 +8,7 @@ * Dancer * Dancer::Plugin::Database -* DBD::mysql +* DBD::MariaDB * Starman (if using Starman as web server) * Plack (for plackup) * nginx (if you want to front Dancer with nginx, nginx.conf provided) @@ -22,3 +22,4 @@ Something along the lines of if you want to front it with nginx, otherwise plackup -E production -s Starman --port=8080 --workers=2 -a ./app.pl + diff --git a/frameworks/Perl/dancer/app.pl b/frameworks/Perl/dancer/app.pl index dd58de39896..65ab9d2a6a3 100755 --- a/frameworks/Perl/dancer/app.pl +++ b/frameworks/Perl/dancer/app.pl @@ -8,8 +8,8 @@ set serializer => 'JSON'; -my $dsn = "dbi:mysql:database=hello_world;host=tfb-database;port=3306"; -my $dbh = DBI->connect( $dsn, 'benchmarkdbuser', 'benchmarkdbpass', { mysql_auto_reconnect=>1 } ); +my $dsn = "dbi:MariaDB:database=hello_world;host=tfb-database;port=3306"; +my $dbh = DBI->connect( $dsn, 'benchmarkdbuser', 'benchmarkdbpass' ); my $sth = $dbh->prepare("SELECT * FROM World where id = ?"); get '/json' => sub { @@ -20,7 +20,7 @@ my $queries = params->{queries} || 1; $queries = 1 if ( $queries !~ /^\d+$/ || $queries < 1 ); $queries = 500 if $queries > 500; - + my @response; for ( 1 .. $queries ) { my $id = int rand 10000 + 1; @@ -42,3 +42,4 @@ }; Dancer->dance; + diff --git a/frameworks/Perl/dancer/benchmark_config.json b/frameworks/Perl/dancer/benchmark_config.json index 94408b910f7..306909555ae 100644 --- a/frameworks/Perl/dancer/benchmark_config.json +++ b/frameworks/Perl/dancer/benchmark_config.json @@ -19,7 +19,8 @@ "display_name": "dancer", "notes": "", "versus": "", - "tags": ["broken"] + "tags": [] } }] } + diff --git a/frameworks/Perl/dancer/dancer.dockerfile b/frameworks/Perl/dancer/dancer.dockerfile index 687c3825ae9..0094ff8fca8 100644 --- a/frameworks/Perl/dancer/dancer.dockerfile +++ b/frameworks/Perl/dancer/dancer.dockerfile @@ -1,4 +1,4 @@ -FROM perl:5.26 +FROM perl:5.40 RUN apt-get update -yqq && apt-get install -yqq nginx @@ -10,7 +10,7 @@ RUN cpanm --notest --no-man-page \ Dancer@1.3134 \ Dancer::Plugin::Database@2.10 \ DBI@1.633 \ - DBD::mysql@4.033 \ + DBD::MariaDB@1.23 \ JSON::XS@3.01 \ Plack@1.0034 \ Starman@0.4011 @@ -18,4 +18,5 @@ RUN cpanm --notest --no-man-page \ EXPOSE 8080 CMD nginx -c /dancer/nginx.conf && \ - plackup -E production -s Starman --workers=$(nproc) -l /tmp/perl-dancer.sock -a ./app.pl + plackup -E production -s Starman --workers=$(nproc) --max-requests=100000 -l /tmp/perl-dancer.sock -a ./app.pl + diff --git a/frameworks/Perl/kelp/benchmark_config.json b/frameworks/Perl/kelp/benchmark_config.json index 1cd06f51ad0..dc164a11576 100644 --- a/frameworks/Perl/kelp/benchmark_config.json +++ b/frameworks/Perl/kelp/benchmark_config.json @@ -1,7 +1,7 @@ { "framework": "kelp", "tests": [{ - "gazelle-mysql": { + "default": { "dockerfile": "kelp.dockerfile", "plaintext_url": "/plaintext", "json_url": "/json", diff --git a/frameworks/Perl/kelp/run.pl b/frameworks/Perl/kelp/run.pl index b8436498f64..3aaed8d4cf7 100755 --- a/frameworks/Perl/kelp/run.pl +++ b/frameworks/Perl/kelp/run.pl @@ -62,6 +62,10 @@ ], ); +# default is gazelle-mysql (techempower will warn if there is no default) +$test_name = 'kelp-gazelle-mysql' + if $test_name eq 'kelp'; + die "invalid test name $test_name" unless $test_name =~ m{^kelp-(\w+)-(\w+)$}; diff --git a/frameworks/Perl/mojolicious/app.pl b/frameworks/Perl/mojolicious/app.pl index a1e38dd48f6..465c2c7381c 100644 --- a/frameworks/Perl/mojolicious/app.pl +++ b/frameworks/Perl/mojolicious/app.pl @@ -1,18 +1,19 @@ +use v5.36; use Mojolicious::Lite; use Mojo::Pg; use Mojo::Promise; -use Cpanel::JSON::XS 'encode_json'; use Scalar::Util 'looks_like_number'; -use Data::Dumper; # configuration +use constant MAX_DB_CONCURRENCY => 50; + { my $nproc = `nproc`; app->config(hypnotoad => { - accepts => 0, - clients => int( 256 / $nproc ) + 1, + accepts => 100000, + clients => MAX_DB_CONCURRENCY, graceful_timeout => 1, requests => 10000, workers => $nproc, @@ -20,41 +21,33 @@ }); } -{ - my $db_host = 'tfb-database'; - helper pg => sub { state $pg = Mojo::Pg->new('postgresql://benchmarkdbuser:benchmarkdbpass@' . $db_host . '/hello_world')->max_connections(50) }; -} - -helper render_json => sub { - my $c = shift; - $c->res->headers->content_type('application/json'); - $c->render( data => encode_json(shift) ); -}; - # Routes -get '/json' => sub { shift->helpers->render_json({message => 'Hello, World!'}) }; +get '/json' => sub ($c) { + $c->render(json => {message => 'Hello, World!'}); +}; -get '/db' => sub { shift->helpers->render_query(1, {single => 1}) }; +get '/db' => sub ($c) { + $c->helpers->render_query(1, {single => 1}); +}; -get '/queries' => sub { - my $c = shift; +get '/queries' => sub ($c) { $c->helpers->render_query(scalar $c->param('queries')); }; -get '/fortunes' => sub { - my $c = shift; +get '/fortunes' => sub ($c) { $c->render_later; - my $docs = $c->helpers->pg->db->query_p('SELECT id, message FROM Fortune') - ->then(sub{ - my $docs = $_[0]->arrays; - push @$docs, [0, 'Additional fortune added at request time.']; - $c->render(fortunes => docs => $docs->sort(sub{ $a->[1] cmp $b->[1] }) ) - }); + + $c->helpers->pg->db->query_p('SELECT id, message FROM Fortune') + ->then(sub ($query) { + my $docs = $query->arrays; + push @$docs, [0, 'Additional fortune added at request time.']; + + $c->render(fortunes => docs => $docs->sort(sub { $a->[1] cmp $b->[1] })); + }); }; -get '/updates' => sub { - my $c = shift; +get '/updates' => sub ($c) { $c->helpers->render_query(scalar $c->param('queries'), {update => 1}); }; @@ -62,55 +55,47 @@ # Additional helpers (shared code) -helper 'render_query' => sub { - my ($self, $q, $args) = @_; +helper pg => sub { + state $pg = Mojo::Pg + ->new('postgresql://benchmarkdbuser:benchmarkdbpass@tfb-database/hello_world') + ->max_connections(MAX_DB_CONCURRENCY + 1); +}; + +helper 'render_query' => sub ($self, $q, $args = {}) { $self->render_later; - $args ||= {}; - my $update = $args->{update}; $q = 1 unless looks_like_number($q); $q = 1 if $q < 1; $q = 500 if $q > 500; - my $r = []; - my $tx = $self->tx; + Mojo::Promise->map({concurrency => MAX_DB_CONCURRENCY}, sub { + my $db = $self->helpers->pg->db; + my $id = 1 + int rand 10_000; + my $query = $db->query('SELECT id, randomnumber FROM World WHERE id=?', $id); + my $number = $query->array->[1]; - my @queries; - foreach (1 .. $q) { - my $id = 1 + int rand 10_000; + if ($args->{update}) { + $number = 1 + int rand 10_000; + $db->query('UPDATE World SET randomnumber=? WHERE id=?', $number, $id); + } - push @queries, $self->helpers->pg->db->query_p('SELECT id,randomnumber FROM World WHERE id=?', $id) - ->then(sub{ - my $randomNumber = $_[0]->array->[0]; - - return Mojo::Promise->new->resolve($id, $randomNumber) - ->then(sub{ - if($update) { - $randomNumber = 1 + int rand 10_000; - return Mojo::Promise->all( - Mojo::Promise->new->resolve($_[0], $randomNumber), - $self->helpers->pg->db->query_p('UPDATE World SET randomnumber=? WHERE id=?', $randomNumber, $id) - ) - ->then(sub { - return $_[0]; - }) - } - return [shift, shift]; - }) - }); - } + return Mojo::Promise->resolve([$id, $number]); + }, 1 .. $q) + ->then(sub (@responses) { + my @results; - Mojo::Promise->all(@queries) - ->then(sub{ - my @responses = @_; foreach my $resp (@responses) { - push @$r, { id => $resp->[0][0], randomNumber => $resp->[0][1] }; + push @results, { id => $resp->[0][0], randomNumber => $resp->[0][1] }; } - $r = $r->[0] if $args->{single}; - $self->helpers->render_json($r); - }) + if ($args->{single}) { + $self->render(json => $results[0]); + } + else { + $self->render(json => \@results); + } + }); }; app->start; @@ -133,3 +118,4 @@ + diff --git a/frameworks/Perl/mojolicious/cpanfile b/frameworks/Perl/mojolicious/cpanfile index 12f340c183e..68299a759ce 100644 --- a/frameworks/Perl/mojolicious/cpanfile +++ b/frameworks/Perl/mojolicious/cpanfile @@ -1,7 +1,8 @@ requires 'Mojolicious', '7.84'; requires 'Mojo::Pg', '4.08'; -requires 'Cpanel::JSON::XS', '4.02'; +requires 'Cpanel::JSON::XS', '4.38'; requires 'EV', '4.22'; recommends 'IO::Socket::IP', '0.36'; recommends 'IO::Socket::SSL'; + diff --git a/frameworks/Perl/mojolicious/cpanfile.snapshot b/frameworks/Perl/mojolicious/cpanfile.snapshot index a43dcb6688e..c3f7c9e074b 100644 --- a/frameworks/Perl/mojolicious/cpanfile.snapshot +++ b/frameworks/Perl/mojolicious/cpanfile.snapshot @@ -1,15 +1,15 @@ # carton snapshot format: version 1.0 DISTRIBUTIONS - Canary-Stability-2012 - pathname: M/ML/MLEHMANN/Canary-Stability-2012.tar.gz + Canary-Stability-2013 + pathname: M/ML/MLEHMANN/Canary-Stability-2013.tar.gz provides: - Canary::Stability 2012 + Canary::Stability 2013 requirements: ExtUtils::MakeMaker 0 - Class-Method-Modifiers-2.12 - pathname: E/ET/ETHER/Class-Method-Modifiers-2.12.tar.gz + Class-Method-Modifiers-2.15 + pathname: E/ET/ETHER/Class-Method-Modifiers-2.15.tar.gz provides: - Class::Method::Modifiers 2.12 + Class::Method::Modifiers 2.15 requirements: B 0 Carp 0 @@ -27,27 +27,36 @@ DISTRIBUTIONS ExtUtils::MakeMaker 0 Storable 0 perl 5.008001 - Cpanel-JSON-XS-4.02 - pathname: R/RU/RURBAN/Cpanel-JSON-XS-4.02.tar.gz + Cpanel-JSON-XS-4.38 + pathname: R/RU/RURBAN/Cpanel-JSON-XS-4.38.tar.gz provides: - Cpanel::JSON::XS 4.02 + Cpanel::JSON::XS 4.38 Cpanel::JSON::XS::Type undef requirements: + Carp 0 + Config 0 + Encode 1.9801 + Exporter 0 ExtUtils::MakeMaker 0 Pod::Text 2.08 - DBD-Pg-3.7.4 - pathname: T/TU/TURNSTEP/DBD-Pg-3.7.4.tar.gz + XSLoader 0 + overload 0 + strict 0 + warnings 0 + DBD-Pg-3.18.0 + pathname: T/TU/TURNSTEP/DBD-Pg-3.18.0.tar.gz provides: - Bundle::DBD::Pg v3.7.4 - DBD::Pg v3.7.4 + Bundle::DBD::Pg v3.18.0 + DBD::Pg v3.18.0 requirements: DBI 1.614 - ExtUtils::MakeMaker 6.11 + ExtUtils::MakeMaker 6.58 + File::Temp 0 Test::More 0.88 Time::HiRes 0 version 0 - DBI-1.641 - pathname: T/TI/TIMB/DBI-1.641.tar.gz + DBI-1.643 + pathname: T/TI/TIMB/DBI-1.643.tar.gz provides: Bundle::DBI 12.008696 DBD::DBM 0.08 @@ -103,7 +112,7 @@ DISTRIBUTIONS DBD::Sponge::dr 12.010003 DBD::Sponge::st 12.010003 DBDI 12.015129 - DBI 1.641 + DBI 1.643 DBI::Const::GetInfo::ANSI 2.008697 DBI::Const::GetInfo::ODBC 2.011374 DBI::Const::GetInfoReturn 2.008697 @@ -143,128 +152,60 @@ DISTRIBUTIONS DBI::SQL::Nano::Table_ 1.015544 DBI::Util::CacheMemory 0.010315 DBI::Util::_accessor 0.009479 - DBI::common 1.641 + DBI::common 1.643 requirements: ExtUtils::MakeMaker 6.48 Test::Simple 0.90 - perl 5.008 - Devel-GlobalDestruction-0.14 - pathname: H/HA/HAARG/Devel-GlobalDestruction-0.14.tar.gz - provides: - Devel::GlobalDestruction 0.14 - requirements: - ExtUtils::MakeMaker 0 - Sub::Exporter::Progressive 0.001011 - perl 5.006 - EV-4.22 - pathname: M/ML/MLEHMANN/EV-4.22.tar.gz + perl 5.008001 + EV-4.34 + pathname: M/ML/MLEHMANN/EV-4.34.tar.gz provides: - EV 4.22 + EV 4.34 EV::MakeMaker undef requirements: Canary::Stability 0 ExtUtils::MakeMaker 6.52 common::sense 0 - Hash-Merge-0.300 - pathname: R/RE/REHSACK/Hash-Merge-0.300.tar.gz + Hash-Merge-0.302 + pathname: H/HE/HERMES/Hash-Merge-0.302.tar.gz provides: - Hash::Merge 0.300 + Hash::Merge 0.302 requirements: Clone::Choose 0.008 ExtUtils::MakeMaker 6.64 Scalar::Util 0 perl 5.008001 - MRO-Compat-0.13 - pathname: H/HA/HAARG/MRO-Compat-0.13.tar.gz + MRO-Compat-0.15 + pathname: H/HA/HAARG/MRO-Compat-0.15.tar.gz provides: - MRO::Compat 0.13 + MRO::Compat 0.15 requirements: ExtUtils::MakeMaker 0 perl 5.006 - Module-Build-0.4224 - pathname: L/LE/LEONT/Module-Build-0.4224.tar.gz - provides: - Module::Build 0.4224 - Module::Build::Base 0.4224 - Module::Build::Compat 0.4224 - Module::Build::Config 0.4224 - Module::Build::Cookbook 0.4224 - Module::Build::Dumper 0.4224 - Module::Build::Notes 0.4224 - Module::Build::PPMMaker 0.4224 - Module::Build::Platform::Default 0.4224 - Module::Build::Platform::MacOS 0.4224 - Module::Build::Platform::Unix 0.4224 - Module::Build::Platform::VMS 0.4224 - Module::Build::Platform::VOS 0.4224 - Module::Build::Platform::Windows 0.4224 - Module::Build::Platform::aix 0.4224 - Module::Build::Platform::cygwin 0.4224 - Module::Build::Platform::darwin 0.4224 - Module::Build::Platform::os2 0.4224 - Module::Build::PodParser 0.4224 - requirements: - CPAN::Meta 2.142060 - CPAN::Meta::YAML 0.003 - Cwd 0 - Data::Dumper 0 - ExtUtils::CBuilder 0.27 - ExtUtils::Install 0 - ExtUtils::Manifest 0 - ExtUtils::Mkbootstrap 0 - ExtUtils::ParseXS 2.21 - File::Basename 0 - File::Compare 0 - File::Copy 0 - File::Find 0 - File::Path 0 - File::Spec 0.82 - File::Temp 0.15 - Getopt::Long 0 - Module::Metadata 1.000002 - Parse::CPAN::Meta 1.4401 - Perl::OSType 1 - Pod::Man 2.17 - TAP::Harness 3.29 - Test::More 0.49 - Text::Abbrev 0 - Text::ParseWords 0 - perl 5.006001 - version 0.87 - Module-Runtime-0.016 - pathname: Z/ZE/ZEFRAM/Module-Runtime-0.016.tar.gz - provides: - Module::Runtime 0.016 - requirements: - Module::Build 0 - Test::More 0.41 - perl 5.006 - strict 0 - warnings 0 - Mojo-Pg-4.08 - pathname: S/SR/SRI/Mojo-Pg-4.08.tar.gz + Mojo-Pg-4.27 + pathname: S/SR/SRI/Mojo-Pg-4.27.tar.gz provides: - Mojo::Pg 4.08 + Mojo::Pg 4.27 Mojo::Pg::Database undef Mojo::Pg::Migrations undef Mojo::Pg::PubSub undef Mojo::Pg::Results undef Mojo::Pg::Transaction undef - SQL::Abstract::Pg undef requirements: - DBD::Pg 3.005001 + DBD::Pg 3.007004 ExtUtils::MakeMaker 0 - Mojolicious 7.53 - SQL::Abstract 1.85 - perl 5.010001 - Mojolicious-7.84 - pathname: S/SR/SRI/Mojolicious-7.84.tar.gz + Mojolicious 8.50 + SQL::Abstract::Pg 1.0 + perl 5.016 + Mojolicious-9.37 + pathname: S/SR/SRI/Mojolicious-9.37.tar.gz provides: Mojo undef Mojo::Asset undef Mojo::Asset::File undef Mojo::Asset::Memory undef Mojo::Base undef + Mojo::BaseUtil undef Mojo::ByteStream undef Mojo::Cache undef Mojo::Collection undef @@ -278,6 +219,7 @@ DISTRIBUTIONS Mojo::DOM::CSS undef Mojo::DOM::HTML undef Mojo::Date undef + Mojo::DynamicMethods undef Mojo::EventEmitter undef Mojo::Exception undef Mojo::File undef @@ -286,13 +228,8 @@ DISTRIBUTIONS Mojo::Home undef Mojo::IOLoop undef Mojo::IOLoop::Client undef - Mojo::IOLoop::Delay undef Mojo::IOLoop::Server undef Mojo::IOLoop::Stream undef - Mojo::IOLoop::Stream::HTTPClient undef - Mojo::IOLoop::Stream::HTTPServer undef - Mojo::IOLoop::Stream::WebSocketClient undef - Mojo::IOLoop::Stream::WebSocketServer undef Mojo::IOLoop::Subprocess undef Mojo::IOLoop::TLS undef Mojo::JSON undef @@ -316,7 +253,6 @@ DISTRIBUTIONS Mojo::Server::Morbo::Backend undef Mojo::Server::Morbo::Backend::Poll undef Mojo::Server::PSGI undef - Mojo::Server::PSGI::_IO undef Mojo::Server::Prefork undef Mojo::Template undef Mojo::Transaction undef @@ -331,37 +267,36 @@ DISTRIBUTIONS Mojo::UserAgent::Transactor undef Mojo::Util undef Mojo::WebSocket undef - Mojolicious 7.84 + Mojolicious 9.37 Mojolicious::Command undef + Mojolicious::Command::Author::cpanify undef + Mojolicious::Command::Author::generate undef + Mojolicious::Command::Author::generate::app undef + Mojolicious::Command::Author::generate::dockerfile undef + Mojolicious::Command::Author::generate::lite_app undef + Mojolicious::Command::Author::generate::makefile undef + Mojolicious::Command::Author::generate::plugin undef + Mojolicious::Command::Author::inflate undef Mojolicious::Command::cgi undef - Mojolicious::Command::cpanify undef Mojolicious::Command::daemon undef Mojolicious::Command::eval undef - Mojolicious::Command::generate undef - Mojolicious::Command::generate::app undef - Mojolicious::Command::generate::lite_app undef - Mojolicious::Command::generate::makefile undef - Mojolicious::Command::generate::plugin undef Mojolicious::Command::get undef - Mojolicious::Command::inflate undef Mojolicious::Command::prefork undef Mojolicious::Command::psgi undef Mojolicious::Command::routes undef - Mojolicious::Command::test undef Mojolicious::Command::version undef Mojolicious::Commands undef Mojolicious::Controller undef Mojolicious::Lite undef Mojolicious::Plugin undef Mojolicious::Plugin::Config undef - Mojolicious::Plugin::Config::Sandbox undef Mojolicious::Plugin::DefaultHelpers undef Mojolicious::Plugin::EPLRenderer undef Mojolicious::Plugin::EPRenderer undef Mojolicious::Plugin::HeaderCondition undef Mojolicious::Plugin::JSONConfig undef Mojolicious::Plugin::Mount undef - Mojolicious::Plugin::PODRenderer undef + Mojolicious::Plugin::NotYAMLConfig undef Mojolicious::Plugin::TagHelpers undef Mojolicious::Plugins undef Mojolicious::Renderer undef @@ -379,52 +314,55 @@ DISTRIBUTIONS requirements: ExtUtils::MakeMaker 0 IO::Socket::IP 0.37 - JSON::PP 2.27103 - Pod::Simple 3.09 - Time::Local 1.2 - perl 5.010001 - Moo-2.003004 - pathname: H/HA/HAARG/Moo-2.003004.tar.gz + Sub::Util 1.41 + perl 5.016 + Moo-2.005005 + pathname: H/HA/HAARG/Moo-2.005005.tar.gz provides: Method::Generate::Accessor undef Method::Generate::BuildAll undef Method::Generate::Constructor undef Method::Generate::DemolishAll undef - Moo 2.003004 + Moo 2.005005 Moo::HandleMoose undef Moo::HandleMoose::FakeConstructor undef Moo::HandleMoose::FakeMetaClass undef Moo::HandleMoose::_TypeMap undef Moo::Object undef - Moo::Role 2.003004 + Moo::Role 2.005005 Moo::_Utils undef - Moo::_mro undef - Moo::_strictures undef Moo::sification undef oo undef requirements: - Class::Method::Modifiers 1.1 - Devel::GlobalDestruction 0.11 - Exporter 5.57 + Carp 0 + Class::Method::Modifiers 1.10 + Exporter 0 ExtUtils::MakeMaker 0 - Module::Runtime 0.014 - Role::Tiny 2.000004 - Scalar::Util 0 - Sub::Defer 2.003001 - Sub::Quote 2.003001 + Role::Tiny 2.002003 + Scalar::Util 1.00 + Sub::Defer 2.006006 + Sub::Quote 2.006006 perl 5.006 - Role-Tiny-2.000006 - pathname: H/HA/HAARG/Role-Tiny-2.000006.tar.gz + Role-Tiny-2.002004 + pathname: H/HA/HAARG/Role-Tiny-2.002004.tar.gz provides: - Role::Tiny 2.000006 - Role::Tiny::With 2.000006 + Role::Tiny 2.002004 + Role::Tiny::With 2.002004 requirements: Exporter 5.57 perl 5.006 - SQL-Abstract-1.85 - pathname: I/IL/ILMARI/SQL-Abstract-1.85.tar.gz + SQL-Abstract-2.000001 + pathname: M/MS/MSTROUT/SQL-Abstract-2.000001.tar.gz provides: - SQL::Abstract 1.85 + Chunkstrumenter undef + DBIx::Class::SQLMaker::Role::SQLA2Passthrough undef + SQL::Abstract 2.000001 + SQL::Abstract::Formatter undef + SQL::Abstract::Parts undef + SQL::Abstract::Plugin::BangOverrides undef + SQL::Abstract::Plugin::ExtraClauses undef + SQL::Abstract::Reference undef + SQL::Abstract::Role::Plugin undef SQL::Abstract::Test undef SQL::Abstract::Tree undef requirements: @@ -436,26 +374,91 @@ DISTRIBUTIONS Moo 2.000001 Scalar::Util 0 Sub::Quote 2.000001 + Test::Builder::Module 0.84 + Test::Deep 0.101 Text::Balanced 2.00 perl 5.006 - Sub-Exporter-Progressive-0.001013 - pathname: F/FR/FREW/Sub-Exporter-Progressive-0.001013.tar.gz + SQL-Abstract-Pg-1.0 + pathname: S/SR/SRI/SQL-Abstract-Pg-1.0.tar.gz provides: - Sub::Exporter::Progressive 0.001013 + SQL::Abstract::Pg 1.0 requirements: ExtUtils::MakeMaker 0 - Sub-Quote-2.005001 - pathname: H/HA/HAARG/Sub-Quote-2.005001.tar.gz + SQL::Abstract 2.0 + perl 5.016 + Sub-Quote-2.006008 + pathname: H/HA/HAARG/Sub-Quote-2.006008.tar.gz provides: - Sub::Defer 2.005001 - Sub::Quote 2.005001 + Sub::Defer 2.006008 + Sub::Quote 2.006008 requirements: ExtUtils::MakeMaker 0 Scalar::Util 0 perl 5.006 - common-sense-3.74 - pathname: M/ML/MLEHMANN/common-sense-3.74.tar.gz + Test-Deep-1.204 + pathname: R/RJ/RJBS/Test-Deep-1.204.tar.gz + provides: + Test::Deep 1.204 + Test::Deep::All 1.204 + Test::Deep::Any 1.204 + Test::Deep::Array 1.204 + Test::Deep::ArrayEach 1.204 + Test::Deep::ArrayElementsOnly 1.204 + Test::Deep::ArrayLength 1.204 + Test::Deep::ArrayLengthOnly 1.204 + Test::Deep::Blessed 1.204 + Test::Deep::Boolean 1.204 + Test::Deep::Cache 1.204 + Test::Deep::Cache::Simple 1.204 + Test::Deep::Class 1.204 + Test::Deep::Cmp 1.204 + Test::Deep::Code 1.204 + Test::Deep::Hash 1.204 + Test::Deep::HashEach 1.204 + Test::Deep::HashElements 1.204 + Test::Deep::HashKeys 1.204 + Test::Deep::HashKeysOnly 1.204 + Test::Deep::Ignore 1.204 + Test::Deep::Isa 1.204 + Test::Deep::ListMethods 1.204 + Test::Deep::MM 1.204 + Test::Deep::Methods 1.204 + Test::Deep::NoTest 1.204 + Test::Deep::None 1.204 + Test::Deep::Number 1.204 + Test::Deep::Obj 1.204 + Test::Deep::Ref 1.204 + Test::Deep::RefType 1.204 + Test::Deep::Regexp 1.204 + Test::Deep::RegexpMatches 1.204 + Test::Deep::RegexpOnly 1.204 + Test::Deep::RegexpRef 1.204 + Test::Deep::RegexpRefOnly 1.204 + Test::Deep::RegexpVersion 1.204 + Test::Deep::ScalarRef 1.204 + Test::Deep::ScalarRefOnly 1.204 + Test::Deep::Set 1.204 + Test::Deep::Shallow 1.204 + Test::Deep::Stack 1.204 + Test::Deep::String 1.204 + Test::Deep::SubHash 1.204 + Test::Deep::SubHashElements 1.204 + Test::Deep::SubHashKeys 1.204 + Test::Deep::SubHashKeysOnly 1.204 + Test::Deep::SuperHash 1.204 + Test::Deep::SuperHashElements 1.204 + Test::Deep::SuperHashKeys 1.204 + Test::Deep::SuperHashKeysOnly 1.204 + requirements: + ExtUtils::MakeMaker 6.78 + List::Util 1.09 + Scalar::Util 1.09 + Test::Builder 0 + Test::More 0.96 + perl 5.012 + common-sense-3.75 + pathname: M/ML/MLEHMANN/common-sense-3.75.tar.gz provides: - common::sense 3.74 + common::sense 3.75 requirements: ExtUtils::MakeMaker 0 diff --git a/frameworks/Perl/mojolicious/mojolicious.dockerfile b/frameworks/Perl/mojolicious/mojolicious.dockerfile index fe9197e6233..1fec0cc3952 100644 --- a/frameworks/Perl/mojolicious/mojolicious.dockerfile +++ b/frameworks/Perl/mojolicious/mojolicious.dockerfile @@ -1,4 +1,4 @@ -FROM perl:5.26 +FROM perl:5.40 WORKDIR /mojo @@ -19,3 +19,4 @@ ADD ./app.pl ./ EXPOSE 8080 CMD hypnotoad -f /mojo/app.pl + diff --git a/frameworks/Perl/plack/README.md b/frameworks/Perl/plack/README.md index f8172775ec1..d08e9a91a20 100644 --- a/frameworks/Perl/plack/README.md +++ b/frameworks/Perl/plack/README.md @@ -9,4 +9,5 @@ Plack * Twiggy::Prefork * JSON::XS * AnyEvent::DBI -* DBD::mysql +* DBD::MariaDB + diff --git a/frameworks/Perl/plack/app-async.psgi b/frameworks/Perl/plack/app-async.psgi index 93df1c50b2d..b5397d1ca5e 100644 --- a/frameworks/Perl/plack/app-async.psgi +++ b/frameworks/Perl/plack/app-async.psgi @@ -5,7 +5,7 @@ use AnyEvent::DBI; use Unix::Processors; use List::Util qw'min max'; -my @dsn = ('dbi:mysql:database=hello_world;host=tfb-database;port=3306', 'benchmarkdbuser', 'benchmarkdbpass'); +my @dsn = ('dbi:MariaDB:database=hello_world;host=tfb-database;port=3306', 'benchmarkdbuser', 'benchmarkdbpass'); my $query = 'select randomNumber, id from World where id = ?'; sub { @@ -37,3 +37,4 @@ sub { } [404, [qw(Content-Type application/json)], ['not found']] } + diff --git a/frameworks/Perl/plack/app.pl b/frameworks/Perl/plack/app.pl index c1a1172b277..b62eaa6acdc 100644 --- a/frameworks/Perl/plack/app.pl +++ b/frameworks/Perl/plack/app.pl @@ -7,10 +7,10 @@ my @cmd = ( ($opts->{a} # async server - ? [qw'plackup -s Twiggy::Prefork -E production --max-reqs-per-child=0 --backlog 16384 + ? [qw'plackup -s Twiggy::Prefork -E production --max-reqs-per-child=100000 --backlog 16384 --max-workers', $cpus, qw'-l /dev/shm/app.sock -a app-async.psgi'] : [qw'start_server --backlog 16384 --path /dev/shm/app.sock -- - plackup -s Gazelle -E production --max-reqs-per-child 10000000 + plackup -s Gazelle -E production --max-reqs-per-child 100000 --max-workers', $cpus, qw'-a app.psgi']), [qw'nginx -c nginx.conf -p', getcwd] ); diff --git a/frameworks/Perl/plack/app.psgi b/frameworks/Perl/plack/app.psgi index 4f5d8579d38..dc625076660 100644 --- a/frameworks/Perl/plack/app.psgi +++ b/frameworks/Perl/plack/app.psgi @@ -5,9 +5,9 @@ use List::Util qw'min max'; sub { state $dbh = DBI->connect( - 'dbi:mysql:database=hello_world;host=tfb-database;port=3306', + 'dbi:MariaDB:database=hello_world;host=tfb-database;port=3306', 'benchmarkdbuser', 'benchmarkdbpass', - +{ qw'RaiseError 0 PrintError 0 mysql_enable_utf8 1' } + +{ qw'RaiseError 0 PrintError 0' } ) || die $!; state $sth = $dbh->prepare('select id,randomnumber from world where id = ?'); my $env = shift; @@ -25,3 +25,4 @@ sub { } [ 404, [], ['not found']]; } + diff --git a/frameworks/Perl/plack/plack-async.dockerfile b/frameworks/Perl/plack/plack-async.dockerfile index 4af66083005..8ef1ac76b04 100644 --- a/frameworks/Perl/plack/plack-async.dockerfile +++ b/frameworks/Perl/plack/plack-async.dockerfile @@ -1,7 +1,7 @@ FROM perl:latest RUN apt-get update -yqq && apt-get install -yqq nginx -RUN cpanm --notest --no-man-page Plack JSON::XS Unix::Processors DBI DBD::mysql +RUN cpanm --notest --no-man-page Plack JSON::XS Unix::Processors DBI DBD::MariaDB RUN cpanm --notest --no-man-page Cookie::Baker::XS Twiggy::Prefork HTTP::Parser::XS EV AnyEvent::DBI ADD nginx.conf ./ @@ -11,3 +11,4 @@ ADD app-async.psgi ./ EXPOSE 8080 CMD perl app.pl -a + diff --git a/frameworks/Perl/plack/plack.dockerfile b/frameworks/Perl/plack/plack.dockerfile index f2a14dd5b4c..a0391f2f4ca 100644 --- a/frameworks/Perl/plack/plack.dockerfile +++ b/frameworks/Perl/plack/plack.dockerfile @@ -1,7 +1,7 @@ FROM perl:latest RUN apt-get update -yqq && apt-get install -yqq nginx -RUN cpanm --notest --no-man-page Plack JSON::XS Unix::Processors DBI DBD::mysql +RUN cpanm --notest --no-man-page Plack JSON::XS Unix::Processors DBI DBD::MariaDB RUN cpanm --notest --no-man-page Gazelle Cookie::Baker::XS ADD nginx.conf ./ @@ -11,3 +11,4 @@ ADD app.psgi ./ EXPOSE 8080 CMD perl app.pl + diff --git a/frameworks/Perl/web-simple/README.md b/frameworks/Perl/web-simple/README.md index d169c515914..98e8d6a836e 100644 --- a/frameworks/Perl/web-simple/README.md +++ b/frameworks/Perl/web-simple/README.md @@ -7,7 +7,7 @@ # Requirements * Web::Simple -* DBD::mysql +* DBD::MariaDB * Starman (if using Starman as web server) * Plack (for plackup) * nginx (if you want to front Dancer with nginx, nginx.conf provided) @@ -21,3 +21,4 @@ Something along the lines of if you want to front it with nginx, otherwise plackup -E production -s Starman --port=8080 --workers=8 -a ./app.pl + diff --git a/frameworks/Perl/web-simple/app.pl b/frameworks/Perl/web-simple/app.pl index d2db3e11299..2447c765c01 100755 --- a/frameworks/Perl/web-simple/app.pl +++ b/frameworks/Perl/web-simple/app.pl @@ -4,7 +4,7 @@ use DBI; sub get_database_handle { - DBI->connect_cached('dbi:mysql:database=hello_world;host=tfb-database', 'benchmarkdbuser', 'benchmarkdbpass', { RaiseError => 1 }); + DBI->connect_cached('dbi:MariaDB:database=hello_world;host=tfb-database', 'benchmarkdbuser', 'benchmarkdbpass', { RaiseError => 1 }); } sub dispatch_request { @@ -54,3 +54,4 @@ sub dispatch_request { } __PACKAGE__->run_if_script; + diff --git a/frameworks/Perl/web-simple/benchmark_config.json b/frameworks/Perl/web-simple/benchmark_config.json index 629b19df0c1..6725005d211 100644 --- a/frameworks/Perl/web-simple/benchmark_config.json +++ b/frameworks/Perl/web-simple/benchmark_config.json @@ -19,7 +19,8 @@ "display_name": "web-simple", "notes": "", "versus": "", - "tags": ["broken"] + "tags": [] } }] } + diff --git a/frameworks/Perl/web-simple/web-simple.dockerfile b/frameworks/Perl/web-simple/web-simple.dockerfile index f3b83b7a7c0..5a2678bfe1b 100644 --- a/frameworks/Perl/web-simple/web-simple.dockerfile +++ b/frameworks/Perl/web-simple/web-simple.dockerfile @@ -1,4 +1,4 @@ -FROM perl:5.26 +FROM perl:5.40 RUN apt-get update -yqq && apt-get install -yqq nginx @@ -8,7 +8,7 @@ RUN cpanm --notest --no-man-page \ JSON JSON::XS IO::Socket::IP IO::Socket::SSL \ Web::Simple@0.033 \ DBI@1.637 \ - DBD::mysql@4.043 \ + DBD::MariaDB@1.23 \ Plack@1.0044 \ Starman@0.4014 \ JSON::XS@3.04 @@ -21,4 +21,6 @@ EXPOSE 8080 CMD nginx -c /simple/nginx.conf && \ plackup -E production -s Starman --workers=$(nproc) \ + --max-requests=100000 \ -l /tmp/perl-simple.sock -a /simple/app.pl + From 411a25b56a646df27a8b4d583b2fb866875308ae Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 9 Jul 2024 22:00:04 +0000 Subject: [PATCH 027/204] Bump google.golang.org/grpc in /frameworks/Go/goravel/src/fiber Bumps [google.golang.org/grpc](https://github.com/grpc/grpc-go) from 1.64.0 to 1.64.1. - [Release notes](https://github.com/grpc/grpc-go/releases) - [Commits](https://github.com/grpc/grpc-go/compare/v1.64.0...v1.64.1) --- updated-dependencies: - dependency-name: google.golang.org/grpc dependency-type: indirect ... Signed-off-by: dependabot[bot] --- frameworks/Go/goravel/src/fiber/go.mod | 6 +++--- frameworks/Go/goravel/src/fiber/go.sum | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/frameworks/Go/goravel/src/fiber/go.mod b/frameworks/Go/goravel/src/fiber/go.mod index e285c0106e3..b31a4b9ba88 100644 --- a/frameworks/Go/goravel/src/fiber/go.mod +++ b/frameworks/Go/goravel/src/fiber/go.mod @@ -4,8 +4,6 @@ go 1.22 require ( github.com/bytedance/sonic v1.11.9 - github.com/gofiber/fiber/v2 v2.52.4 - github.com/gofiber/template/html/v2 v2.1.1 github.com/goravel/fiber v1.2.1 github.com/goravel/framework v1.14.1 github.com/valyala/quicktemplate v1.7.0 @@ -63,7 +61,9 @@ require ( github.com/go-redsync/redsync/v4 v4.8.1 // indirect github.com/go-sql-driver/mysql v1.8.1 // indirect github.com/go-stack/stack v1.8.0 // indirect + github.com/gofiber/fiber/v2 v2.52.4 // indirect github.com/gofiber/template v1.8.3 // indirect + github.com/gofiber/template/html/v2 v2.1.1 // indirect github.com/gofiber/utils v1.1.0 // indirect github.com/golang-jwt/jwt/v4 v4.5.0 // indirect github.com/golang-jwt/jwt/v5 v5.2.1 // indirect @@ -174,7 +174,7 @@ require ( google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de // indirect google.golang.org/genproto/googleapis/api v0.0.0-20240318140521-94a12d6c2237 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237 // indirect - google.golang.org/grpc v1.64.0 // indirect + google.golang.org/grpc v1.64.1 // indirect google.golang.org/protobuf v1.34.1 // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect diff --git a/frameworks/Go/goravel/src/fiber/go.sum b/frameworks/Go/goravel/src/fiber/go.sum index 942ea9c3e7f..e036eea01cf 100644 --- a/frameworks/Go/goravel/src/fiber/go.sum +++ b/frameworks/Go/goravel/src/fiber/go.sum @@ -1096,8 +1096,8 @@ google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= -google.golang.org/grpc v1.64.0 h1:KH3VH9y/MgNQg1dE7b3XfVK0GsPSIzJwdF617gUSbvY= -google.golang.org/grpc v1.64.0/go.mod h1:oxjF8E3FBnjp+/gVFYdWacaLDx9na1aqy9oovLpxQYg= +google.golang.org/grpc v1.64.1 h1:LKtvyfbX3UGVPFcGqJ9ItpVWW6oN/2XqTxfAnwRRXiA= +google.golang.org/grpc v1.64.1/go.mod h1:hiQF4LFZelK2WKaP6W0L92zGHtiQdZxk8CrSdvyjeP0= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= From 14e4e09f660c92be1ca1fd557415950e7bbeaec7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 9 Jul 2024 22:08:43 +0000 Subject: [PATCH 028/204] Bump mysql2 from 3.9.7 to 3.9.8 in /frameworks/JavaScript/sailsjs Bumps [mysql2](https://github.com/sidorares/node-mysql2) from 3.9.7 to 3.9.8. - [Release notes](https://github.com/sidorares/node-mysql2/releases) - [Changelog](https://github.com/sidorares/node-mysql2/blob/master/Changelog.md) - [Commits](https://github.com/sidorares/node-mysql2/compare/v3.9.7...v3.9.8) --- updated-dependencies: - dependency-name: mysql2 dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- frameworks/JavaScript/sailsjs/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frameworks/JavaScript/sailsjs/package.json b/frameworks/JavaScript/sailsjs/package.json index 9be38df56ad..b2886f07639 100644 --- a/frameworks/JavaScript/sailsjs/package.json +++ b/frameworks/JavaScript/sailsjs/package.json @@ -10,7 +10,7 @@ "ejs": "3.1.10", "handlebars": "4.7.6", "mysql": "2.16.0", - "mysql2": "3.9.7", + "mysql2": "3.9.8", "pg": "6.0.5", "pg-hstore": "2.3.2", "rc": "1.1.6", From 11376ea45ca3b9067b24690cc0acc5b7c9fe88cb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 10 Jul 2024 08:42:44 -0700 Subject: [PATCH 029/204] Bump mysql2 from 3.9.7 to 3.9.8 in /frameworks/JavaScript/nodejs (#9154) Bumps [mysql2](https://github.com/sidorares/node-mysql2) from 3.9.7 to 3.9.8. - [Release notes](https://github.com/sidorares/node-mysql2/releases) - [Changelog](https://github.com/sidorares/node-mysql2/blob/master/Changelog.md) - [Commits](https://github.com/sidorares/node-mysql2/compare/v3.9.7...v3.9.8) --- updated-dependencies: - dependency-name: mysql2 dependency-type: direct:production ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- frameworks/JavaScript/nodejs/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frameworks/JavaScript/nodejs/package.json b/frameworks/JavaScript/nodejs/package.json index 8af5fedae2b..28dc35a011c 100644 --- a/frameworks/JavaScript/nodejs/package.json +++ b/frameworks/JavaScript/nodejs/package.json @@ -8,7 +8,7 @@ "mongodb": "3.7.3", "mongoose": "5.13.20", "mysql": "2.16.0", - "mysql2": "3.9.7", + "mysql2": "3.9.8", "parseurl": "1.3.2", "pg": "8.5.0", "pg-hstore": "2.3.2", From d54303b8cdcd145d074925573c9e914f1ab0fbf9 Mon Sep 17 00:00:00 2001 From: Giovanni Barillari Date: Thu, 11 Jul 2024 19:01:41 +0200 Subject: [PATCH 030/204] [Python] Bump Granian to 1.5.x (#9157) --- frameworks/Python/emmett/requirements.txt | 2 +- frameworks/Python/emmett/run.py | 7 ++++--- frameworks/Python/granian/requirements.txt | 2 +- frameworks/Python/granian/run.py | 13 +++++++++---- 4 files changed, 15 insertions(+), 9 deletions(-) diff --git a/frameworks/Python/emmett/requirements.txt b/frameworks/Python/emmett/requirements.txt index 2c329705017..627a2187091 100644 --- a/frameworks/Python/emmett/requirements.txt +++ b/frameworks/Python/emmett/requirements.txt @@ -1,2 +1,2 @@ -emmett[orjson]>=2.5.3,<2.6.0 +emmett[orjson]>=2.5.12,<2.6.0 psycopg2-binary==2.9.5 diff --git a/frameworks/Python/emmett/run.py b/frameworks/Python/emmett/run.py index 42679101ea0..02a21e458f9 100644 --- a/frameworks/Python/emmett/run.py +++ b/frameworks/Python/emmett/run.py @@ -4,16 +4,17 @@ if __name__ == "__main__": - cpus = multiprocessing.cpu_count() + workers = round(multiprocessing.cpu_count() / 2) run( "rsgi", ("app", "app"), host="0.0.0.0", port=8080, - workers=cpus, + workers=workers, backlog=16384, - threading_mode='runtime', + threading_mode="runtime", + http="1", enable_websockets=False, log_level="warn" ) diff --git a/frameworks/Python/granian/requirements.txt b/frameworks/Python/granian/requirements.txt index e1b7c479119..1a22a3ddfc2 100644 --- a/frameworks/Python/granian/requirements.txt +++ b/frameworks/Python/granian/requirements.txt @@ -1,4 +1,4 @@ asyncpg==0.29.0 -granian>=1.4.2,<1.5.0 +granian>=1.5.1,<1.6.0 jinja2==3.1.4 orjson==3.10.2 diff --git a/frameworks/Python/granian/run.py b/frameworks/Python/granian/run.py index acdad59a542..910b248422b 100644 --- a/frameworks/Python/granian/run.py +++ b/frameworks/Python/granian/run.py @@ -7,9 +7,14 @@ if __name__ == '__main__': interface = sys.argv[1] threading_mode = sys.argv[2] - workers = multiprocessing.cpu_count() - if threading_mode == "workers": - workers = round(workers / 2) + + #: split cores between the two loops + workers = round(multiprocessing.cpu_count() / 2) + + blocking_threads = None + if interface == "wsgi": + #: we don't run any I/O in WSGI benches + blocking_threads = 1 Granian( f"app_{interface}:main", @@ -17,7 +22,7 @@ port=8080, workers=workers, threading_mode=threading_mode, - blocking_threads=1, + blocking_threads=blocking_threads, backlog=16384, interface=interface, http="1", From 0ef534b6fce72f197333d70a3f60362e798bb8e7 Mon Sep 17 00:00:00 2001 From: uNetworkingAB <110806833+uNetworkingAB@users.noreply.github.com> Date: Thu, 11 Jul 2024 19:04:23 +0200 Subject: [PATCH 031/204] Gnet is unrealistic (#9159) * [gnet] is unrealistic * Update benchmark_config.json --- frameworks/Go/gnet/benchmark_config.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/frameworks/Go/gnet/benchmark_config.json b/frameworks/Go/gnet/benchmark_config.json index 484ec41b8ff..3999bd74f97 100644 --- a/frameworks/Go/gnet/benchmark_config.json +++ b/frameworks/Go/gnet/benchmark_config.json @@ -4,8 +4,8 @@ "default": { "plaintext_url": "/plaintext", "port": 8080, - "approach": "Realistic", - "classification": "Platform", + "approach": "stripped", + "classification": "Micro", "database": "None", "framework": "gnet", "language": "Go", @@ -20,4 +20,4 @@ "versus": "go" } }] -} \ No newline at end of file +} From 4b0a91f07147386c8f11b36b1410f00b34c7611c Mon Sep 17 00:00:00 2001 From: Nate Date: Thu, 11 Jul 2024 10:22:13 -0700 Subject: [PATCH 032/204] Remove uwebsockets (#9160) --- .../JavaScript/uwebsockets.js/README.md | 55 ----- .../uwebsockets.js/benchmark_config.json | 68 ------ .../uwebsockets.js/package-lock.json | 105 ---------- .../JavaScript/uwebsockets.js/package.json | 18 -- .../uwebsockets.js/src/clustered.js | 23 --- .../uwebsockets.js/src/database/mysql.js | 16 -- .../uwebsockets.js/src/database/postgres.js | 17 -- .../JavaScript/uwebsockets.js/src/server.js | 194 ------------------ .../JavaScript/uwebsockets.js/src/utils.js | 86 -------- .../uwebsockets.js-mysql.dockerfile | 12 -- .../uwebsockets.js-postgres.dockerfile | 12 -- .../uwebsockets.js/uwebsockets.js.dockerfile | 11 - 12 files changed, 617 deletions(-) delete mode 100644 frameworks/JavaScript/uwebsockets.js/README.md delete mode 100644 frameworks/JavaScript/uwebsockets.js/benchmark_config.json delete mode 100644 frameworks/JavaScript/uwebsockets.js/package-lock.json delete mode 100644 frameworks/JavaScript/uwebsockets.js/package.json delete mode 100644 frameworks/JavaScript/uwebsockets.js/src/clustered.js delete mode 100644 frameworks/JavaScript/uwebsockets.js/src/database/mysql.js delete mode 100644 frameworks/JavaScript/uwebsockets.js/src/database/postgres.js delete mode 100644 frameworks/JavaScript/uwebsockets.js/src/server.js delete mode 100644 frameworks/JavaScript/uwebsockets.js/src/utils.js delete mode 100644 frameworks/JavaScript/uwebsockets.js/uwebsockets.js-mysql.dockerfile delete mode 100644 frameworks/JavaScript/uwebsockets.js/uwebsockets.js-postgres.dockerfile delete mode 100644 frameworks/JavaScript/uwebsockets.js/uwebsockets.js.dockerfile diff --git a/frameworks/JavaScript/uwebsockets.js/README.md b/frameworks/JavaScript/uwebsockets.js/README.md deleted file mode 100644 index 73fc530d673..00000000000 --- a/frameworks/JavaScript/uwebsockets.js/README.md +++ /dev/null @@ -1,55 +0,0 @@ -# uWebSockets.js Benchmarking Test - -uWebSockets is a web server written in C/C++ (https://github.com/uNetworking/uWebSockets) - -µWebSockets.js is a web server bypass for Node.js (https://github.com/uNetworking/uWebSockets.js) - -## Important Libraries - -The tests were run with: - -- [uWebSockets.js](https://github.com/uNetworking/uWebSockets.js/) -- [postgres](https://github.com/porsager/postgres/) -- [mariadb](https://github.com/mariadb-corporation/mariadb-connector-nodejs/) - -## Database - -There are individual handlers for each DB approach. The logic for each of them are found here: - -- [PostgreSQL](src/database/postgres.js) -- [MySQL](src/database/mysql.js) - -There are **no database endpoints** or drivers attached by default. - -To initialize the application with one of these, run any _one_ of the following commands: - -```sh -$ DATABASE=postgres npm start -$ DATABASE=mysql npm start -``` - -## Test Endpoints - -> Visit the test requirements [here](https://github.com/TechEmpower/FrameworkBenchmarks/wiki/Project-Information-Framework-Tests-Overview) - -```sh -$ curl localhost:8080/json -$ curl localhost:8080/plaintext - -# The following are only available with the DATABASE env var - -$ curl localhost:8080/db -$ curl localhost:8080/fortunes - -$ curl localhost:8080/updates?queries= -$ curl localhost:8080/updates?queries=2 -$ curl localhost:8080/updates?queries=1000 -$ curl localhost:8080/updates?queries=foo -$ curl localhost:8080/updates?queries=0 - -$ curl localhost:8080/queries?queries= -$ curl localhost:8080/queries?queries=2 -$ curl localhost:8080/queries?queries=1000 -$ curl localhost:8080/queries?queries=foo -$ curl localhost:8080/queries?queries=0 -``` diff --git a/frameworks/JavaScript/uwebsockets.js/benchmark_config.json b/frameworks/JavaScript/uwebsockets.js/benchmark_config.json deleted file mode 100644 index fee055f341a..00000000000 --- a/frameworks/JavaScript/uwebsockets.js/benchmark_config.json +++ /dev/null @@ -1,68 +0,0 @@ -{ - "framework": "uwebsockets.js", - "tests": [ - { - "default": { - "approach": "Realistic", - "classification": "Platform", - "database": "None", - "database_os": "Linux", - "display_name": "uWebSockets.js", - "flavor": "NodeJS", - "framework": "uWebSockets.js", - "json_url": "/json", - "language": "JavaScript", - "notes": "", - "orm": "Raw", - "os": "Linux", - "plaintext_url": "/plaintext", - "platform": "nodejs", - "port": 8080, - "versus": "nodejs", - "webserver": "None" - }, - "postgres": { - "approach": "Realistic", - "classification": "Platform", - "database": "Postgres", - "database_os": "Linux", - "db_url": "/db", - "display_name": "uWebSockets.js", - "flavor": "NodeJS", - "fortune_url": "/fortunes", - "framework": "uWebSockets.js", - "language": "JavaScript", - "notes": "", - "orm": "Raw", - "os": "Linux", - "platform": "None", - "port": 8080, - "query_url": "/queries?queries=", - "update_url": "/updates?queries=", - "versus": "nodejs", - "webserver": "None" - }, - "mysql": { - "approach": "Realistic", - "classification": "Platform", - "database": "MySQL", - "database_os": "Linux", - "db_url": "/db", - "display_name": "uWebSockets.js", - "flavor": "NodeJS", - "fortune_url": "/fortunes", - "framework": "uWebSockets.js", - "language": "JavaScript", - "notes": "", - "orm": "Raw", - "os": "Linux", - "platform": "None", - "port": 8080, - "query_url": "/queries?queries=", - "update_url": "/updates?queries=", - "versus": "nodejs", - "webserver": "None" - } - } - ] -} diff --git a/frameworks/JavaScript/uwebsockets.js/package-lock.json b/frameworks/JavaScript/uwebsockets.js/package-lock.json deleted file mode 100644 index 910703e95b8..00000000000 --- a/frameworks/JavaScript/uwebsockets.js/package-lock.json +++ /dev/null @@ -1,105 +0,0 @@ -{ - "name": "uwebsockets.js", - "version": "0.0.1", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "uwebsockets.js", - "version": "0.0.1", - "license": "MIT", - "dependencies": { - "mariadb": "^3.3.0", - "postgres": "^3.4.4", - "slow-json-stringify": "^2.0.1", - "uWebSockets.js": "uNetworking/uWebSockets.js#v20.44.0" - } - }, - "node_modules/@types/geojson": { - "version": "7946.0.14", - "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.14.tgz", - "integrity": "sha512-WCfD5Ht3ZesJUsONdhvm84dmzWOiOzOAqOncN0++w0lBw1o8OuDNJF2McvvCef/yBqb/HYRahp1BYtODFQ8bRg==" - }, - "node_modules/@types/node": { - "version": "20.12.7", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.7.tgz", - "integrity": "sha512-wq0cICSkRLVaf3UGLMGItu/PtdY7oaXaI/RVU+xliKVOtRna3PRY57ZDfztpDL0n11vfymMUnXv8QwYCO7L1wg==", - "dependencies": { - "undici-types": "~5.26.4" - } - }, - "node_modules/denque": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/denque/-/denque-2.1.0.tgz", - "integrity": "sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==", - "engines": { - "node": ">=0.10" - } - }, - "node_modules/iconv-lite": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", - "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/lru-cache": { - "version": "10.2.2", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.2.tgz", - "integrity": "sha512-9hp3Vp2/hFQUiIwKo8XCeFVnrg8Pk3TYNPIR7tJADKi5YfcF7vEaK7avFHTlSy3kOKYaJQaalfEo6YuXdceBOQ==", - "engines": { - "node": "14 || >=16.14" - } - }, - "node_modules/mariadb": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/mariadb/-/mariadb-3.3.0.tgz", - "integrity": "sha512-sAL4bJgbfCAtXcE8bXI+NAMzVaPNkIU8hRZUXYfgNFoWB9U57G3XQiMeCx/A6IrS6y7kGwBLylrwgsZQ8kUYlw==", - "dependencies": { - "@types/geojson": "^7946.0.14", - "@types/node": "^20.11.17", - "denque": "^2.1.0", - "iconv-lite": "^0.6.3", - "lru-cache": "^10.2.0" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/postgres": { - "version": "3.4.4", - "resolved": "https://registry.npmjs.org/postgres/-/postgres-3.4.4.tgz", - "integrity": "sha512-IbyN+9KslkqcXa8AO9fxpk97PA4pzewvpi2B3Dwy9u4zpV32QicaEdgmF3eSQUzdRk7ttDHQejNgAEr4XoeH4A==", - "engines": { - "node": ">=12" - }, - "funding": { - "type": "individual", - "url": "https://github.com/sponsors/porsager" - } - }, - "node_modules/safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" - }, - "node_modules/slow-json-stringify": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/slow-json-stringify/-/slow-json-stringify-2.0.1.tgz", - "integrity": "sha512-jqyzIqTaSkRGcWdWqjmOLKHZgOGUT71ZCTsvQu1xGu9Mqaod7O26y5FJJEmaUQhaTWh0bkXv2qqN0i+EQsD1jQ==" - }, - "node_modules/undici-types": { - "version": "5.26.5", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", - "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==" - }, - "node_modules/uWebSockets.js": { - "version": "20.44.0", - "resolved": "git+ssh://git@github.com/uNetworking/uWebSockets.js.git#8fa05571bf6ea95be8966ad313d9d39453e381ae" - } - } -} diff --git a/frameworks/JavaScript/uwebsockets.js/package.json b/frameworks/JavaScript/uwebsockets.js/package.json deleted file mode 100644 index ec5bc0c1d73..00000000000 --- a/frameworks/JavaScript/uwebsockets.js/package.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "dependencies": { - "mariadb": "^3.3.0", - "postgres": "^3.4.4", - "slow-json-stringify": "^2.0.1", - "uWebSockets.js": "uNetworking/uWebSockets.js#v20.44.0" - }, - "license": "MIT", - "main": "src/server.js", - "name": "uwebsockets.js", - "private": true, - "scripts": { - "dev": "node src/server.js", - "start": "node src/clustered.js" - }, - "type": "module", - "version": "0.0.1" -} diff --git a/frameworks/JavaScript/uwebsockets.js/src/clustered.js b/frameworks/JavaScript/uwebsockets.js/src/clustered.js deleted file mode 100644 index 95a57ec77f3..00000000000 --- a/frameworks/JavaScript/uwebsockets.js/src/clustered.js +++ /dev/null @@ -1,23 +0,0 @@ -import cluster from "node:cluster"; -import os from "node:os"; -import process from "node:process"; - -if (cluster.isPrimary) { - // Master Node - console.log(`Primary ${process.pid} is running`); - - // Fork workers - const numCPUs = os.availableParallelism(); - for (let i = 0; i < numCPUs; i++) { - cluster.fork(); - } - - cluster.on("exit", (worker) => { - console.log(`worker ${worker.process.pid} died`); - process.exit(1); - }); -} else { - // Cluster Node - await import("./server.js"); - console.log(`Worker ${process.pid} started`); -} diff --git a/frameworks/JavaScript/uwebsockets.js/src/database/mysql.js b/frameworks/JavaScript/uwebsockets.js/src/database/mysql.js deleted file mode 100644 index a627a74d132..00000000000 --- a/frameworks/JavaScript/uwebsockets.js/src/database/mysql.js +++ /dev/null @@ -1,16 +0,0 @@ -import { createPool } from "mariadb"; -import os from "node:os"; - -const pool = createPool({ - host: "tfb-database", - user: "benchmarkdbuser", - password: "benchmarkdbpass", - database: "hello_world", - connectionLimit: os.availableParallelism() -}); - -export const fortunes = async () => await pool.execute("SELECT id, message FROM fortune"); - -export const find = async (id) => await pool.execute("SELECT id, randomnumber FROM world WHERE id = ?", [id]).then((arr) => arr[0]); - -export const bulkUpdate = async (worlds) => await Promise.all(worlds.map(world => pool.execute("UPDATE world SET randomnumber = ? WHERE id = ?", [world.randomNumber, world.id]))); diff --git a/frameworks/JavaScript/uwebsockets.js/src/database/postgres.js b/frameworks/JavaScript/uwebsockets.js/src/database/postgres.js deleted file mode 100644 index 105eeef99e5..00000000000 --- a/frameworks/JavaScript/uwebsockets.js/src/database/postgres.js +++ /dev/null @@ -1,17 +0,0 @@ -import postgres from "postgres"; - -const sql = postgres({ - host: "tfb-database", - user: "benchmarkdbuser", - password: "benchmarkdbpass", - database: "hello_world", - max: 1 -}); - -export const fortunes = async () => await sql`SELECT id, message FROM fortune`; - -export const find = async (id) => await sql`SELECT id, randomNumber FROM world WHERE id = ${id}`.then((arr) => arr[0]); - -export const bulkUpdate = async (worlds) => await sql`UPDATE world SET randomNumber = (update_data.randomNumber)::int - FROM (VALUES ${sql(worlds.map(world => [world.id, world.randomNumber]).sort((a, b) => (a[0] < b[0]) ? -1 : 1))}) AS update_data (id, randomNumber) - WHERE world.id = (update_data.id)::int`; diff --git a/frameworks/JavaScript/uwebsockets.js/src/server.js b/frameworks/JavaScript/uwebsockets.js/src/server.js deleted file mode 100644 index 1db7d391f2a..00000000000 --- a/frameworks/JavaScript/uwebsockets.js/src/server.js +++ /dev/null @@ -1,194 +0,0 @@ -import uWebSockets from "uWebSockets.js"; -import { - addBenchmarkHeaders, - generateRandomNumber, - getQueriesCount, - handleError, - escape, - jsonSerializer, - worldObjectSerializer, - sortByMessage -} from "./utils.js"; - -let db; -const { DATABASE } = process.env; -if (DATABASE) db = await import(`./database/${DATABASE}.js`); - -const webserver = uWebSockets.App(); - -webserver.get("/plaintext", new uWebSockets.DeclarativeResponse() - .writeHeader("Server", "uWebSockets.js") - .writeHeader("Content-Type", "text/plain") - .end("Hello, World!") -); - -webserver.get("/json", (response) => { - addBenchmarkHeaders(response); - response.writeHeader("Content-Type", "application/json"); - // response.end(JSON.stringify({ message: "Hello, World!" })); - response.end(jsonSerializer({ message: "Hello, World!" })); -}); - -if (db) { - webserver.get("/db", async (response) => { - response.onAborted(() => { - response.aborted = true; - }); - - try { - const row = await db.find(generateRandomNumber()); - - if (response.aborted) { - return; - } - - response.cork(() => { - addBenchmarkHeaders(response); - response.writeHeader("Content-Type", "application/json"); - // response.end(JSON.stringify(rows)); - response.end(worldObjectSerializer(row)); - }); - } catch (error) { - if (response.aborted) { - return; - } - - handleError(error, response); - } - }); - - webserver.get("/queries", async (response, request) => { - response.onAborted(() => { - response.aborted = true; - }); - - try { - const queriesCount = getQueriesCount(request); - - const databaseJobs = new Array(queriesCount); - - for (let i = 0; i < queriesCount; i++) { - databaseJobs[i] = db.find(generateRandomNumber()); - } - - const worldObjects = await Promise.all(databaseJobs); - - if (response.aborted) { - return; - } - - response.cork(() => { - addBenchmarkHeaders(response); - response.writeHeader("Content-Type", "application/json"); - response.end(JSON.stringify(worldObjects)); - }); - } catch (error) { - if (response.aborted) { - return; - } - - handleError(error, response); - } - }); - - const extra = { id: 0, message: "Additional fortune added at request time." }; - - webserver.get("/fortunes", async (response) => { - response.onAborted(() => { - response.aborted = true; - }); - - try { - const rows = [extra, ...await db.fortunes()]; - - if (response.aborted) { - return; - } - - // rows.push({ - // id: 0, - // message: "Additional fortune added at request time.", - // }); - - // rows.sort((a, b) => (a.message < b.message) ? -1 : 1); - sortByMessage(rows) - - const n = rows.length - - let html = "", i = 0; - for (; i < n; i++) { - html += `${rows[i].id}${escape(rows[i].message)}`; - } - - response.cork(() => { - addBenchmarkHeaders(response); - response.writeHeader("Content-Type", "text/html; charset=utf-8"); - response.end(`Fortunes${html}
idmessage
`); - }); - } catch (error) { - if (response.aborted) { - return; - } - - handleError(error, response); - } - }); - - webserver.get("/updates", async (response, request) => { - response.onAborted(() => { - response.aborted = true; - }); - - try { - const queriesCount = getQueriesCount(request); - - const databaseJobs = new Array(queriesCount); - - for (let i = 0; i < queriesCount; i++) { - databaseJobs[i] = db.find(generateRandomNumber()); - } - - const worldObjects = await Promise.all(databaseJobs); - - for (let i = 0; i < queriesCount; i++) { - worldObjects[i].randomNumber = generateRandomNumber(); - } - - await db.bulkUpdate(worldObjects); - - if (response.aborted) { - return; - } - - response.cork(() => { - addBenchmarkHeaders(response); - response.writeHeader("Content-Type", "application/json"); - response.end(JSON.stringify(worldObjects)); - }); - } catch (error) { - if (response.aborted) { - return; - } - - handleError(error, response); - } - }); -} - -webserver.any("/*", (response) => { - response.writeStatus("404 Not Found"); - addBenchmarkHeaders(response); - response.writeHeader("Content-Type", "text/plain"); - response.end("Not Found"); -}); - -const host = process.env.HOST || "0.0.0.0"; -const port = parseInt(process.env.PORT || "8080"); -webserver.listen(host, port, (socket) => { - if (!socket) { - console.error(`Couldn't bind to http://${host}:${port}!`); - process.exit(1); - } - - console.log(`Successfully bound to http://${host}:${port}.`); -}); diff --git a/frameworks/JavaScript/uwebsockets.js/src/utils.js b/frameworks/JavaScript/uwebsockets.js/src/utils.js deleted file mode 100644 index b3d46e7e11c..00000000000 --- a/frameworks/JavaScript/uwebsockets.js/src/utils.js +++ /dev/null @@ -1,86 +0,0 @@ -import { sjs, attr } from 'slow-json-stringify' - -/** - * Add Benchmark HTTP response headers. - * - * Add HTTP response headers `Server` which is required by the test suite. - * Header `Date` is automatically added by uWebsockets - * https://github.com/uNetworking/uWebSockets/blob/master/src/HttpResponse.h#L78 - * - * https://github.com/TechEmpower/FrameworkBenchmarks/wiki/Project-Information-Framework-Tests-Overview - * - * @param {import('uWebSockets.js').HttpResponse} response - */ -export function addBenchmarkHeaders(response) { - response.writeHeader("Server", "uWebSockets.js"); -} - -/** - * Handle error for response - * - * @param {Error} error - * @param {import('uWebSockets.js').HttpResponse} response - */ -export function handleError(error, response) { - console.error(error); - response.cork(() => { - addBenchmarkHeaders(response); - response.writeHeader("Content-Type", "text/plain"); - response.end("Internal Server Error"); - }); -} - -/** - * Get queries count - * - * @param {import('uWebSockets.js').HttpRequest} request - */ -export function getQueriesCount(request) { - return Math.min(parseInt(request.getQuery("queries")) || 1, 500); -} - -/** - * Generate random number - * - */ -export function generateRandomNumber() { - return Math.ceil(Math.random() * 10000); -} - -/** - * Escape unsafe HTML Code - * - */ -const escapeHTMLRules = { '&': '&', '<': '<', '>': '>', '"': '"', "'": ''', '/': '/' } - -const unsafeHTMLMatcher = /[&<>"'\/]/g - -export function escape(text) { - if (unsafeHTMLMatcher.test(text) === false) return text; - return text.replace(unsafeHTMLMatcher, function (m) { return escapeHTMLRules[m] || m; }); -} - -/** - * Using Slow json stringify module to get faster results - */ -export const jsonSerializer = sjs({ message: attr("string")}); -export const worldObjectSerializer = sjs({ id: attr('number'), randomnumber: attr('number') }); -// export const worldObjectsSerializer = sjs({ rows: attr("array", worldObjectSerializer) }); - -/** - * Using Sort method which is performant for the test scenario - * @returns - */ -export function sortByMessage (arr) { - const n = arr.length - for (let i = 1; i < n; i++) { - const c = arr[i] - let j = i - 1 - while ((j > -1) && (c.message < arr[j].message)) { - arr[j + 1] = arr[j] - j-- - } - arr[j + 1] = c - } - return arr -} \ No newline at end of file diff --git a/frameworks/JavaScript/uwebsockets.js/uwebsockets.js-mysql.dockerfile b/frameworks/JavaScript/uwebsockets.js/uwebsockets.js-mysql.dockerfile deleted file mode 100644 index 8533d8b9a61..00000000000 --- a/frameworks/JavaScript/uwebsockets.js/uwebsockets.js-mysql.dockerfile +++ /dev/null @@ -1,12 +0,0 @@ -FROM node:20-slim - -COPY ./ ./ - -RUN npm install - -ENV NODE_ENV production -ENV DATABASE mysql - -EXPOSE 8080 - -CMD ["npm", "start"] diff --git a/frameworks/JavaScript/uwebsockets.js/uwebsockets.js-postgres.dockerfile b/frameworks/JavaScript/uwebsockets.js/uwebsockets.js-postgres.dockerfile deleted file mode 100644 index ba7d0eee5f6..00000000000 --- a/frameworks/JavaScript/uwebsockets.js/uwebsockets.js-postgres.dockerfile +++ /dev/null @@ -1,12 +0,0 @@ -FROM node:20-slim - -COPY ./ ./ - -RUN npm install - -ENV NODE_ENV production -ENV DATABASE postgres - -EXPOSE 8080 - -CMD ["npm", "start"] diff --git a/frameworks/JavaScript/uwebsockets.js/uwebsockets.js.dockerfile b/frameworks/JavaScript/uwebsockets.js/uwebsockets.js.dockerfile deleted file mode 100644 index 4262ad19953..00000000000 --- a/frameworks/JavaScript/uwebsockets.js/uwebsockets.js.dockerfile +++ /dev/null @@ -1,11 +0,0 @@ -FROM node:20-slim - -COPY ./ ./ - -RUN npm install - -ENV NODE_ENV production - -EXPOSE 8080 - -CMD ["npm", "start"] From 4022ec349164c56929c47d283302ad531cac3d26 Mon Sep 17 00:00:00 2001 From: Nate Date: Thu, 11 Jul 2024 10:47:19 -0700 Subject: [PATCH 033/204] Code of conduct (#9161) --- CODE_OF_CONDUCT.md | 133 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 133 insertions(+) create mode 100644 CODE_OF_CONDUCT.md diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 00000000000..38838d563cc --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,133 @@ + +# Contributor Covenant Code of Conduct + +## Our Pledge + +We as members, contributors, and leaders pledge to make participation in our +community a harassment-free experience for everyone, regardless of age, body +size, visible or invisible disability, ethnicity, sex characteristics, gender +identity and expression, level of experience, education, socio-economic status, +nationality, personal appearance, race, caste, color, religion, or sexual +identity and orientation. + +We pledge to act and interact in ways that contribute to an open, welcoming, +diverse, inclusive, and healthy community. + +## Our Standards + +Examples of behavior that contributes to a positive environment for our +community include: + +* Demonstrating empathy and kindness toward other people +* Being respectful of differing opinions, viewpoints, and experiences +* Giving and gracefully accepting constructive feedback +* Accepting responsibility and apologizing to those affected by our mistakes, + and learning from the experience +* Focusing on what is best not just for us as individuals, but for the overall + community + +Examples of unacceptable behavior include: + +* The use of sexualized language or imagery, and sexual attention or advances of + any kind +* Trolling, insulting or derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or email address, + without their explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Enforcement Responsibilities + +Community leaders are responsible for clarifying and enforcing our standards of +acceptable behavior and will take appropriate and fair corrective action in +response to any behavior that they deem inappropriate, threatening, offensive, +or harmful. + +Community leaders have the right and responsibility to remove, edit, or reject +comments, commits, code, wiki edits, issues, and other contributions that are +not aligned to this Code of Conduct, and will communicate reasons for moderation +decisions when appropriate. + +## Scope + +This Code of Conduct applies within all community spaces, and also applies when +an individual is officially representing the community in public spaces. +Examples of representing our community include using an official email address, +posting via an official social media account, or acting as an appointed +representative at an online or offline event. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported to the community leaders responsible for enforcement at +tfb@techempower.com. +All complaints will be reviewed and investigated promptly and fairly. + +All community leaders are obligated to respect the privacy and security of the +reporter of any incident. + +## Enforcement Guidelines + +Community leaders will follow these Community Impact Guidelines in determining +the consequences for any action they deem in violation of this Code of Conduct: + +### 1. Correction + +**Community Impact**: Use of inappropriate language or other behavior deemed +unprofessional or unwelcome in the community. + +**Consequence**: A private, written warning from community leaders, providing +clarity around the nature of the violation and an explanation of why the +behavior was inappropriate. A public apology may be requested. + +### 2. Warning + +**Community Impact**: A violation through a single incident or series of +actions. + +**Consequence**: A warning with consequences for continued behavior. No +interaction with the people involved, including unsolicited interaction with +those enforcing the Code of Conduct, for a specified period of time. This +includes avoiding interactions in community spaces as well as external channels +like social media. Violating these terms may lead to a temporary or permanent +ban. + +### 3. Temporary Ban + +**Community Impact**: A serious violation of community standards, including +sustained inappropriate behavior. + +**Consequence**: A temporary ban from any sort of interaction or public +communication with the community for a specified period of time. No public or +private interaction with the people involved, including unsolicited interaction +with those enforcing the Code of Conduct, is allowed during this period. +Violating these terms may lead to a permanent ban. + +### 4. Permanent Ban + +**Community Impact**: Demonstrating a pattern of violation of community +standards, including sustained inappropriate behavior, harassment of an +individual, or aggression toward or disparagement of classes of individuals. + +**Consequence**: A permanent ban from any sort of public interaction within the +community. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], +version 2.1, available at +[https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1]. + +Community Impact Guidelines were inspired by +[Mozilla's code of conduct enforcement ladder][Mozilla CoC]. + +For answers to common questions about this code of conduct, see the FAQ at +[https://www.contributor-covenant.org/faq][FAQ]. Translations are available at +[https://www.contributor-covenant.org/translations][translations]. + +[homepage]: https://www.contributor-covenant.org +[v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html +[Mozilla CoC]: https://github.com/mozilla/diversity +[FAQ]: https://www.contributor-covenant.org/faq +[translations]: https://www.contributor-covenant.org/translations From 562e515c5ce3b956861cd089dd5ac3e9d8e61622 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 12 Jul 2024 21:01:40 +0000 Subject: [PATCH 034/204] Bump org.apache.wicket:wicket-core in /frameworks/Java/wicket Bumps org.apache.wicket:wicket-core from 9.6.0 to 9.18.0. --- updated-dependencies: - dependency-name: org.apache.wicket:wicket-core dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- frameworks/Java/wicket/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frameworks/Java/wicket/pom.xml b/frameworks/Java/wicket/pom.xml index ec30df52f27..c0f0303051d 100644 --- a/frameworks/Java/wicket/pom.xml +++ b/frameworks/Java/wicket/pom.xml @@ -24,7 +24,7 @@ 11 2.13.0 1.7.25 - 9.6.0 + 9.18.0 From d2c0d69d7ba404a04f24808f86a1c6f46ad5720c Mon Sep 17 00:00:00 2001 From: Petrik de Heus Date: Tue, 16 Jul 2024 17:48:06 +0200 Subject: [PATCH 035/204] [rails] Enable YJIT after boot (#9163) There is no need to run the JIT on code that is only used during boot. This is also the new default in newer Rails applications. --- .../Ruby/rails/config/initializers/enable_yjit.rb | 11 +++++++++++ frameworks/Ruby/rails/rails-mysql.dockerfile | 2 +- frameworks/Ruby/rails/rails.dockerfile | 3 ++- 3 files changed, 14 insertions(+), 2 deletions(-) create mode 100644 frameworks/Ruby/rails/config/initializers/enable_yjit.rb diff --git a/frameworks/Ruby/rails/config/initializers/enable_yjit.rb b/frameworks/Ruby/rails/config/initializers/enable_yjit.rb new file mode 100644 index 00000000000..963858ab4c6 --- /dev/null +++ b/frameworks/Ruby/rails/config/initializers/enable_yjit.rb @@ -0,0 +1,11 @@ +# Automatically enable YJIT as of Ruby 3.3, as it bring very +# sizeable performance improvements. + +# If you are deploying to a memory constrained environment +# you may want to delete this file, but otherwise it's free +# performance. +if defined? RubyVM::YJIT.enable + Rails.application.config.after_initialize do + RubyVM::YJIT.enable + end +end diff --git a/frameworks/Ruby/rails/rails-mysql.dockerfile b/frameworks/Ruby/rails/rails-mysql.dockerfile index ae512cbdafd..b14a3b75af6 100644 --- a/frameworks/Ruby/rails/rails-mysql.dockerfile +++ b/frameworks/Ruby/rails/rails-mysql.dockerfile @@ -5,7 +5,7 @@ RUN apt-get update -yqq && apt-get install -yqq --no-install-recommends redis-se EXPOSE 8080 WORKDIR /rails -ENV RUBY_YJIT_ENABLE=1 +# ENV RUBY_YJIT_ENABLE=1 YJIT is enabled in config/initializers/enable_yjit.rb # Use Jemalloc RUN apt-get update && \ diff --git a/frameworks/Ruby/rails/rails.dockerfile b/frameworks/Ruby/rails/rails.dockerfile index 99c16e935bb..392920be9c4 100644 --- a/frameworks/Ruby/rails/rails.dockerfile +++ b/frameworks/Ruby/rails/rails.dockerfile @@ -5,7 +5,8 @@ RUN apt-get update -yqq && apt-get install -yqq --no-install-recommends redis-se EXPOSE 8080 WORKDIR /rails -ENV RUBY_YJIT_ENABLE=1 +# ENV RUBY_YJIT_ENABLE=1 YJIT is enabled in config/initializers/enable_yjit.rb + # Use Jemalloc RUN apt-get update && \ apt-get install -y --no-install-recommends libjemalloc2 From 93918507a4b9ce2d35f4e40596acde022dda8498 Mon Sep 17 00:00:00 2001 From: Petrik de Heus Date: Tue, 16 Jul 2024 17:48:42 +0200 Subject: [PATCH 036/204] [ruby/roda] Use rapidjson for faster JSON serialization (#9164) --- frameworks/Ruby/roda-sequel/Gemfile | 2 +- frameworks/Ruby/roda-sequel/boot.rb | 5 +---- frameworks/Ruby/roda-sequel/hello_world.rb | 8 ++++---- 3 files changed, 6 insertions(+), 9 deletions(-) diff --git a/frameworks/Ruby/roda-sequel/Gemfile b/frameworks/Ruby/roda-sequel/Gemfile index c9c6a48ab89..e511bb3d848 100644 --- a/frameworks/Ruby/roda-sequel/Gemfile +++ b/frameworks/Ruby/roda-sequel/Gemfile @@ -7,7 +7,7 @@ gem "sequel", "~> 5.67" gem "roda", "~> 3.66" gem "tilt", "~> 2.1", require: "tilt/erb" gem "unicorn", "~> 6.1", platforms: %i[ruby mswin], require: false -gem "oj", "~> 3.14" +gem "rapidjson" group :mysql do gem "mysql2", "~> 0.5", platforms: %i[ruby mswin] diff --git a/frameworks/Ruby/roda-sequel/boot.rb b/frameworks/Ruby/roda-sequel/boot.rb index ebeb5a584c4..bc7277e2362 100644 --- a/frameworks/Ruby/roda-sequel/boot.rb +++ b/frameworks/Ruby/roda-sequel/boot.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true require "bundler/setup" require "time" -require "oj" +require "rapidjson" MAX_PK = 10_000 QUERY_RANGE = (1..MAX_PK).freeze ALL_IDS = QUERY_RANGE.to_a @@ -9,9 +9,6 @@ QUERIES_MAX = 500 SEQUEL_NO_ASSOCIATIONS = true -# Use the OJ gem instead of the JSON one -Oj.mimic_JSON() - SERVER_STRING = if defined?(PhusionPassenger) [ diff --git a/frameworks/Ruby/roda-sequel/hello_world.rb b/frameworks/Ruby/roda-sequel/hello_world.rb index 6a0a43efccb..458e1a7c687 100644 --- a/frameworks/Ruby/roda-sequel/hello_world.rb +++ b/frameworks/Ruby/roda-sequel/hello_world.rb @@ -22,13 +22,13 @@ def rand1 # Test type 1: JSON serialization r.is "json" do response[CONTENT_TYPE] = JSON_TYPE - { message: "Hello, World!" }.to_json + RapidJSON.encode({ message: "Hello, World!" }) end # Test type 2: Single database query r.is "db" do response[CONTENT_TYPE] = JSON_TYPE - World.with_pk(rand1).values.to_json + RapidJSON.encode(World.with_pk(rand1).values) end # Test type 3: Multiple database queries @@ -40,7 +40,7 @@ def rand1 World.with_pk(id).values end end - worlds.to_json + RapidJSON.encode(worlds) end # Test type 4: Fortunes @@ -70,7 +70,7 @@ def rand1 end World.batch_update(worlds) end - worlds.map(&:values).to_json + RapidJSON.encode(worlds.map!(&:values)) end # Test type 6: Plaintext From e1dcb73c829d2a7b76d45a436522a4fec3489fde Mon Sep 17 00:00:00 2001 From: Petrik de Heus Date: Tue, 16 Jul 2024 17:48:59 +0200 Subject: [PATCH 037/204] [ruby/rack] Enable Rubys M:N thread scheduler for Puma (#8678) With the M:N thread scheduler thread creation and management cost are reduced. --- frameworks/Ruby/rack/rack.dockerfile | 1 + 1 file changed, 1 insertion(+) diff --git a/frameworks/Ruby/rack/rack.dockerfile b/frameworks/Ruby/rack/rack.dockerfile index e40bfced37a..b9b39c43122 100644 --- a/frameworks/Ruby/rack/rack.dockerfile +++ b/frameworks/Ruby/rack/rack.dockerfile @@ -1,6 +1,7 @@ FROM ruby:3.4-rc ENV RUBY_YJIT_ENABLE=1 +ENV RUBY_MN_THREADS=1 # Use Jemalloc RUN apt-get update && \ From 527c38d3dcc3967feca67a93730b1d0780c43e8a Mon Sep 17 00:00:00 2001 From: Edgar Espina Date: Tue, 16 Jul 2024 11:49:14 -0400 Subject: [PATCH 038/204] jooby: upgrade 3.2.4 (#9156) - get back threadlocal buffer for fortunes - implements vertx like sql updates --- frameworks/Java/jooby/pom.xml | 4 +- .../src/main/java/com/techempower/App.java | 9 +-- .../main/java/com/techempower/PgClient.java | 75 +++++++++++++++---- .../main/java/com/techempower/ReactivePg.java | 18 +---- .../rocker/BufferRockerOutput.java | 65 ++++++++++++++++ 5 files changed, 134 insertions(+), 37 deletions(-) create mode 100644 frameworks/Java/jooby/src/main/java/com/techempower/rocker/BufferRockerOutput.java diff --git a/frameworks/Java/jooby/pom.xml b/frameworks/Java/jooby/pom.xml index 338f8ca065d..bd6ce1a1c68 100644 --- a/frameworks/Java/jooby/pom.xml +++ b/frameworks/Java/jooby/pom.xml @@ -11,8 +11,8 @@ jooby - 3.1.2 - 4.1.110.Final + 3.2.4 + 4.1.111.Final 2.0.2 42.7.3 UTF-8 diff --git a/frameworks/Java/jooby/src/main/java/com/techempower/App.java b/frameworks/Java/jooby/src/main/java/com/techempower/App.java index f7cf3373b4a..7a75f05d60b 100644 --- a/frameworks/Java/jooby/src/main/java/com/techempower/App.java +++ b/frameworks/Java/jooby/src/main/java/com/techempower/App.java @@ -28,13 +28,8 @@ public class App extends Jooby { private static final byte[] MESSAGE_BYTES = MESSAGE.getBytes(StandardCharsets.US_ASCII); - private static final ByteBuffer MESSAGE_BUFFER = (ByteBuffer) ByteBuffer - .allocateDirect(MESSAGE_BYTES.length) - .put(MESSAGE_BYTES) - .flip(); - { - + var bufferFactory = getBufferFactory(); /** Database: */ install(new HikariModule()); DataSource ds = require(DataSource.class); @@ -43,7 +38,7 @@ public class App extends Jooby { install(new RockerModule()); get("/plaintext", ctx -> - ctx.send(MESSAGE_BUFFER.duplicate()) + ctx.send(bufferFactory.wrap(MESSAGE_BYTES)) ); get("/json", ctx -> ctx diff --git a/frameworks/Java/jooby/src/main/java/com/techempower/PgClient.java b/frameworks/Java/jooby/src/main/java/com/techempower/PgClient.java index 4847ddab1de..dd5e9197f01 100644 --- a/frameworks/Java/jooby/src/main/java/com/techempower/PgClient.java +++ b/frameworks/Java/jooby/src/main/java/com/techempower/PgClient.java @@ -1,5 +1,7 @@ package com.techempower; +import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import java.util.concurrent.ExecutionException; import java.util.function.BiConsumer; @@ -32,10 +34,13 @@ public class PgClient { private static final String SELECT_FORTUNE = "SELECT id, message from FORTUNE"; private static class DbConnection { + private SqlClientInternal queries; private PreparedQuery> SELECT_WORLD_QUERY; private PreparedQuery> SELECT_FORTUNE_QUERY; private PreparedQuery> UPDATE_WORLD_QUERY; - private SqlClientInternal connection; + private SqlClientInternal updates; + @SuppressWarnings("unchecked") + private PreparedQuery>[] AGGREGATED_UPDATE_WORLD_QUERY = new PreparedQuery[128]; } private static class DbConnectionFactory extends ThreadLocal { @@ -64,20 +69,32 @@ private Handler> onSuccess(Handler handler) { .setWorkerPoolSize(1) .setInternalBlockingPoolSize(1) ); - var future = PgConnection.connect(vertx, options) + var client1 = PgConnection.connect(vertx, options) .flatMap(conn -> { - result.connection = (SqlClientInternal) conn; + result.queries = (SqlClientInternal) conn; Future f1 = conn.prepare(SELECT_WORLD) .andThen(onSuccess(ps -> result.SELECT_WORLD_QUERY = ps.query())); Future f2 = conn.prepare(SELECT_FORTUNE) .andThen(onSuccess(ps -> result.SELECT_FORTUNE_QUERY = ps.query())); - Future f3 = conn.prepare(UPDATE_WORLD) - .andThen(onSuccess(ps -> result.UPDATE_WORLD_QUERY = ps.query())); - return Future.join(f1, f2, f3); - }) - .toCompletionStage() - .toCompletableFuture() - .get(); + return Future.join(f1, f2); + }); + + var client2 = PgConnection.connect(vertx, options) + .flatMap(conn -> { + result.updates = (SqlClientInternal) conn; + List> list = new ArrayList<>(); + Future f1 = conn.prepare(UPDATE_WORLD) + .andThen(onSuccess(ps -> result.UPDATE_WORLD_QUERY = ps.query())); + list.add(f1); + for (int i = 0; i < result.AGGREGATED_UPDATE_WORLD_QUERY.length; i++) { + int idx = i; + list.add(conn + .prepare(buildAggregatedUpdateQuery(1 + idx)) + .andThen(onSuccess(ps -> result.AGGREGATED_UPDATE_WORLD_QUERY[idx] = ps.query()))); + } + return Future.join(list); + }); + var future = Future.join(client1, client2).toCompletionStage().toCompletableFuture().get(); Throwable cause = future.cause(); if (cause != null) { @@ -91,6 +108,18 @@ private Handler> onSuccess(Handler handler) { throw SneakyThrows.propagate(ex.getCause()); } } + + private static String buildAggregatedUpdateQuery(int len) { + StringBuilder sb = new StringBuilder(); + sb.append("UPDATE world SET randomNumber = update_data.randomNumber FROM (VALUES"); + char sep = ' '; + for (int i = 1;i <= len;i++) { + sb.append(sep).append("($").append(2 * i - 1).append("::int,$").append(2 * i).append("::int)"); + sep = ','; + } + sb.append(") AS update_data (id, randomNumber) WHERE world.id = update_data.id"); + return sb.toString(); + } } private final ThreadLocal sqlClient; @@ -104,7 +133,7 @@ public void selectWorld(Tuple row, Handler>> handler) { } public void selectWorlds(int queries, Handler>> handler) { - this.sqlClient.get().connection.group(c -> { + this.sqlClient.get().queries.group(c -> { for (int i = 0; i < queries; i++) { c.preparedQuery(SELECT_WORLD).execute(Tuple.of(Util.randomWorld()), handler); } @@ -117,7 +146,7 @@ public void fortunes(Handler>> handler) { public void selectWorldForUpdate(int queries, BiConsumer>> consumer) { - this.sqlClient.get().connection.group(c -> { + this.sqlClient.get().queries.group(c -> { PreparedQuery> statement = c.preparedQuery(SELECT_WORLD); for (int i = 0; i < queries; i++) { consumer.accept(i, statement); @@ -125,8 +154,26 @@ public void selectWorldForUpdate(int queries, }); } - public void updateWorld(List batch, Handler>> handler) { - this.sqlClient.get().UPDATE_WORLD_QUERY.executeBatch(batch, handler); + public void updateWorld(World[] worlds, Handler>> handler) { + Arrays.sort(worlds); + int len = worlds.length; + var connection = this.sqlClient.get(); + if (0 < len && len <= connection.AGGREGATED_UPDATE_WORLD_QUERY.length) { + List arguments = new ArrayList<>(); + for (World world : worlds) { + arguments.add(world.getId()); + arguments.add(world.getRandomNumber()); + } + Tuple tuple = Tuple.tuple(arguments); + PreparedQuery> query = connection.AGGREGATED_UPDATE_WORLD_QUERY[len - 1]; + query.execute(tuple, handler); + } else { + List batch = new ArrayList<>(); + for (World world : worlds) { + batch.add(Tuple.of(world.getRandomNumber(), world.getId())); + } + connection.UPDATE_WORLD_QUERY.executeBatch(batch, handler); + } } private PgConnectOptions pgPoolOptions(Config config) { diff --git a/frameworks/Java/jooby/src/main/java/com/techempower/ReactivePg.java b/frameworks/Java/jooby/src/main/java/com/techempower/ReactivePg.java index 6a674c5e8df..c0eef6fb05a 100644 --- a/frameworks/Java/jooby/src/main/java/com/techempower/ReactivePg.java +++ b/frameworks/Java/jooby/src/main/java/com/techempower/ReactivePg.java @@ -7,10 +7,8 @@ import java.util.*; import com.fizzed.rocker.RockerOutputFactory; -import io.jooby.Context; -import io.jooby.Jooby; -import io.jooby.MediaType; -import io.jooby.ServerOptions; +import com.techempower.rocker.BufferRockerOutput; +import io.jooby.*; import io.jooby.rocker.DataBufferOutput; import io.jooby.rocker.RockerModule; import io.vertx.sqlclient.Row; @@ -18,7 +16,6 @@ import io.vertx.sqlclient.Tuple; public class ReactivePg extends Jooby { - { /** Reduce the number of resources due we do reactive processing. */ setServerOptions( @@ -84,14 +81,7 @@ public class ReactivePg extends Jooby { selectCallback.result().iterator().next().getInteger(0), randomWorld()); if (index == queries - 1) { - // Sort results... avoid dead locks - Arrays.sort(result); - List batch = new ArrayList<>(queries); - for (World world : result) { - batch.add(Tuple.of(world.getRandomNumber(), world.getId())); - } - - client.updateWorld(batch, updateCallback -> { + client.updateWorld(result, updateCallback -> { if (updateCallback.failed()) { sendError(ctx, updateCallback.cause()); } else { @@ -106,7 +96,7 @@ public class ReactivePg extends Jooby { }).setNonBlocking(true); /** Fortunes: */ - RockerOutputFactory factory = require(RockerOutputFactory.class); + var factory = BufferRockerOutput.factory(); get("/fortunes", ctx -> { client.fortunes(rsp -> { if (rsp.succeeded()) { diff --git a/frameworks/Java/jooby/src/main/java/com/techempower/rocker/BufferRockerOutput.java b/frameworks/Java/jooby/src/main/java/com/techempower/rocker/BufferRockerOutput.java new file mode 100644 index 00000000000..78abf2056e4 --- /dev/null +++ b/frameworks/Java/jooby/src/main/java/com/techempower/rocker/BufferRockerOutput.java @@ -0,0 +1,65 @@ +package com.techempower.rocker; + +import com.fizzed.rocker.ContentType; +import com.fizzed.rocker.RockerOutput; +import com.fizzed.rocker.RockerOutputFactory; + +import java.io.IOException; +import java.nio.Buffer; +import java.nio.ByteBuffer; +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; + +public class BufferRockerOutput implements RockerOutput { + private final ByteBuffer buffer; + + public BufferRockerOutput(ByteBuffer buffer) { + this.buffer = buffer; + } + + @Override + public ContentType getContentType() { + return ContentType.RAW; + } + + @Override + public Charset getCharset() { + return StandardCharsets.UTF_8; + } + + @Override + public BufferRockerOutput w(String string) throws IOException { + buffer.put(string.getBytes(getCharset())); + return this; + } + + @Override + public BufferRockerOutput w(byte[] bytes) throws IOException { + buffer.put(bytes); + return this; + } + + @Override + public int getByteLength() { + return buffer.remaining(); + } + + public ByteBuffer toBuffer() { + return buffer.flip(); + } + + public static RockerOutputFactory factory() { + var cache = new ThreadLocal() { + @Override + protected BufferRockerOutput initialValue() { + return new BufferRockerOutput(ByteBuffer.allocateDirect(2048)); + } + }; + return (contentType, charsetName) -> cache.get().reset(); + } + + private BufferRockerOutput reset() { + buffer.clear(); + return this; + } +} From 03c1c5c2830aca23f2e29e7f6e46aaaf4ed8b30d Mon Sep 17 00:00:00 2001 From: Ilya Nemtsev Date: Tue, 16 Jul 2024 22:49:35 +0700 Subject: [PATCH 039/204] [Ktor] Latest Ktor, serializer, html dsl versions (#9128) * latest Ktor, serializer, html dsl versions jvm runtime is now 17 Update README.md modernized all ktor tests to jvm 17 and latest ktor small pgclient memory optimizations big cleanup, removed pg-reactive-client, since it's evolution is already being tested a small memory optimization * fixed obsolete config * cleaned up legacy test --- frameworks/Kotlin/ktor/benchmark_config.json | 23 ---- frameworks/Kotlin/ktor/config.toml | 17 --- .../Kotlin/ktor/ktor-asyncdb/build.gradle | 41 ------ .../Kotlin/ktor/ktor-asyncdb/build.gradle.kts | 36 ++++++ .../ktor/ktor-asyncdb/gradle.properties | 4 +- .../gradle/wrapper/gradle-wrapper.properties | 2 +- .../ktor/ktor-asyncdb/src/main/kotlin/main.kt | 118 ++++++------------ frameworks/Kotlin/ktor/ktor-cio.dockerfile | 4 +- .../Kotlin/ktor/ktor-exposed-dao.dockerfile | 2 +- .../Kotlin/ktor/ktor-exposed-dsl.dockerfile | 2 +- .../ktor/ktor-exposed/app/build.gradle.kts | 10 +- frameworks/Kotlin/ktor/ktor-jasync.dockerfile | 4 +- frameworks/Kotlin/ktor/ktor-jetty.dockerfile | 4 +- .../Kotlin/ktor/ktor-pgclient.dockerfile | 4 +- .../ktor/ktor-pgclient/build.gradle.kts | 25 ++-- .../gradle/wrapper/gradle-wrapper.properties | 2 +- .../ktor-pgclient/src/main/kotlin/main.kt | 28 +++-- .../Kotlin/ktor/ktor-reactivepg.dockerfile | 13 -- frameworks/Kotlin/ktor/ktor.dockerfile | 6 +- frameworks/Kotlin/ktor/ktor/README.md | 4 +- frameworks/Kotlin/ktor/ktor/pom.xml | 19 ++- .../org/jetbrains/ktor/benchmarks/Hello.kt | 23 ++-- 22 files changed, 156 insertions(+), 235 deletions(-) delete mode 100644 frameworks/Kotlin/ktor/ktor-asyncdb/build.gradle create mode 100644 frameworks/Kotlin/ktor/ktor-asyncdb/build.gradle.kts delete mode 100644 frameworks/Kotlin/ktor/ktor-reactivepg.dockerfile diff --git a/frameworks/Kotlin/ktor/benchmark_config.json b/frameworks/Kotlin/ktor/benchmark_config.json index f675237f4b9..3a213a240ba 100644 --- a/frameworks/Kotlin/ktor/benchmark_config.json +++ b/frameworks/Kotlin/ktor/benchmark_config.json @@ -94,29 +94,6 @@ "notes": "", "versus": "netty" }, - "reactivepg": { - "json_url": "/json", - "plaintext_url": "/plaintext", - "db_url": "/db", - "query_url": "/query/?queries=", - "fortune_url": "/fortunes", - "update_url": "/updates?queries=", - "port": 8080, - "approach": "Realistic", - "classification": "Fullstack", - "database": "Postgres", - "framework": "Ktor", - "language": "Kotlin", - "flavor": "None", - "orm": "Raw", - "platform": "None", - "webserver": "None", - "os": "Linux", - "database_os": "Linux", - "display_name": "Ktor-reactivepg", - "notes": "", - "versus": "netty" - }, "pgclient": { "plaintext_url": "/plaintext", "json_url": "/json", diff --git a/frameworks/Kotlin/ktor/config.toml b/frameworks/Kotlin/ktor/config.toml index 6077323686d..1c58e63c73f 100644 --- a/frameworks/Kotlin/ktor/config.toml +++ b/frameworks/Kotlin/ktor/config.toml @@ -35,23 +35,6 @@ platform = "None" webserver = "None" versus = "netty" -[reactivepg] -urls.plaintext = "/plaintext" -urls.json = "/json" -urls.db = "/db" -urls.query = "/query/?queries=" -urls.update = "/updates?queries=" -urls.fortune = "/fortunes" -approach = "Realistic" -classification = "Fullstack" -database = "Postgres" -database_os = "Linux" -os = "Linux" -orm = "Raw" -platform = "None" -webserver = "None" -versus = "netty" - [cio] urls.plaintext = "/plaintext" urls.json = "/json" diff --git a/frameworks/Kotlin/ktor/ktor-asyncdb/build.gradle b/frameworks/Kotlin/ktor/ktor-asyncdb/build.gradle deleted file mode 100644 index 9a7b3bf67ee..00000000000 --- a/frameworks/Kotlin/ktor/ktor-asyncdb/build.gradle +++ /dev/null @@ -1,41 +0,0 @@ -plugins { - id "java" - id "application" - id 'org.jetbrains.kotlin.jvm' - id 'kotlinx-serialization' - id 'com.github.johnrengelman.shadow' version '4.0.3' -} - -group 'org.jetbrains.ktor' -version '1.0-SNAPSHOT' - -mainClassName = "MainKt" - -repositories { - mavenCentral() - jcenter() - maven { url "https://kotlin.bintray.com/kotlinx" } -} - -dependencies { - compile "org.jetbrains.kotlin:kotlin-stdlib-jdk8" - compile "org.jetbrains.kotlinx:kotlinx-serialization-runtime:0.9.1" - compile "io.ktor:ktor-server-netty:$ktor_version" - compile "io.ktor:ktor-html-builder:$ktor_version" - compile "com.github.jasync-sql:jasync-postgresql:0.9.39" - compile "io.reactiverse:reactive-pg-client:0.11.3" - compile 'io.vertx:vertx-lang-kotlin-coroutines:3.7.0' -} - -compileKotlin { - kotlinOptions.jvmTarget = "1.8" -} -compileTestKotlin { - kotlinOptions.jvmTarget = "1.8" -} - -shadowJar { - baseName = "bench" - classifier = null - version = null -} diff --git a/frameworks/Kotlin/ktor/ktor-asyncdb/build.gradle.kts b/frameworks/Kotlin/ktor/ktor-asyncdb/build.gradle.kts new file mode 100644 index 00000000000..61cedf013ce --- /dev/null +++ b/frameworks/Kotlin/ktor/ktor-asyncdb/build.gradle.kts @@ -0,0 +1,36 @@ +plugins { + application + kotlin("jvm") version "1.9.22" + kotlin("plugin.serialization") version "2.0.0" + id("com.github.johnrengelman.shadow") version "8.1.0" +} + +group = "org.jetbrains.ktor" +version = "1.0-SNAPSHOT" + +repositories { + mavenCentral() +} + +application { + mainClass.set("MainKt") +} + +val ktor_version = "2.3.12" +val kotlinx_serialization_version = "1.6.3" +val vertx_pg_client = "4.5.8" + +dependencies { + implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:$kotlinx_serialization_version") + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.1") + implementation("io.ktor:ktor-server-netty:$ktor_version") + implementation("io.ktor:ktor-server-default-headers:$ktor_version") + implementation("io.ktor:ktor-server-html-builder:$ktor_version") + implementation("com.github.jasync-sql:jasync-postgresql:2.2.0") +} + +tasks.shadowJar { + archiveBaseName.set("bench") + archiveClassifier.set("") + archiveVersion.set("") +} diff --git a/frameworks/Kotlin/ktor/ktor-asyncdb/gradle.properties b/frameworks/Kotlin/ktor/ktor-asyncdb/gradle.properties index f8ca4442eea..5790d58ceda 100644 --- a/frameworks/Kotlin/ktor/ktor-asyncdb/gradle.properties +++ b/frameworks/Kotlin/ktor/ktor-asyncdb/gradle.properties @@ -1,4 +1,4 @@ kotlin.code.style=official -kotlin_version=1.3.31 -ktor_version=1.2.0 +kotlin_version=1.9.22 +ktor_version=2.3.12 diff --git a/frameworks/Kotlin/ktor/ktor-asyncdb/gradle/wrapper/gradle-wrapper.properties b/frameworks/Kotlin/ktor/ktor-asyncdb/gradle/wrapper/gradle-wrapper.properties index e15293214f9..3d66c176054 100644 --- a/frameworks/Kotlin/ktor/ktor-asyncdb/gradle/wrapper/gradle-wrapper.properties +++ b/frameworks/Kotlin/ktor/ktor-asyncdb/gradle/wrapper/gradle-wrapper.properties @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-4.10-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.0.2-bin.zip diff --git a/frameworks/Kotlin/ktor/ktor-asyncdb/src/main/kotlin/main.kt b/frameworks/Kotlin/ktor/ktor-asyncdb/src/main/kotlin/main.kt index ca7d9e5713e..e9f4221d8ed 100644 --- a/frameworks/Kotlin/ktor/ktor-asyncdb/src/main/kotlin/main.kt +++ b/frameworks/Kotlin/ktor/ktor-asyncdb/src/main/kotlin/main.kt @@ -1,28 +1,21 @@ import com.github.jasync.sql.db.ConnectionPoolConfiguration +import com.github.jasync.sql.db.QueryResult import com.github.jasync.sql.db.SuspendingConnection import com.github.jasync.sql.db.asSuspending import com.github.jasync.sql.db.postgresql.PostgreSQLConnectionBuilder -import io.ktor.application.call -import io.ktor.application.install -import io.ktor.features.DefaultHeaders -import io.ktor.html.Placeholder -import io.ktor.html.Template -import io.ktor.html.insert -import io.ktor.html.respondHtmlTemplate import io.ktor.http.ContentType -import io.ktor.response.respondText -import io.ktor.routing.get -import io.ktor.routing.routing +import io.ktor.server.application.* import io.ktor.server.engine.embeddedServer +import io.ktor.server.html.* import io.ktor.server.netty.Netty -import io.reactiverse.kotlin.pgclient.getConnectionAwait -import io.reactiverse.kotlin.pgclient.preparedBatchAwait -import io.reactiverse.kotlin.pgclient.preparedQueryAwait -import io.reactiverse.pgclient.* +import io.ktor.server.plugins.defaultheaders.* +import io.ktor.server.response.* +import io.ktor.server.routing.* +import kotlinx.coroutines.* import kotlinx.html.* import kotlinx.serialization.Serializable -import kotlinx.serialization.json.JSON -import kotlinx.serialization.list +import kotlinx.serialization.encodeToString +import kotlinx.serialization.json.Json import java.lang.IllegalArgumentException import kotlin.random.Random import kotlin.random.nextInt @@ -44,73 +37,48 @@ interface Repository { } class JasyncRepository() : Repository { - private val dbConfig: ConnectionPoolConfiguration - private val db: SuspendingConnection - - init { - dbConfig = ConnectionPoolConfiguration( - "tfb-database", - database = "hello_world", - username = "benchmarkdbuser", - password = "benchmarkdbpass", - maxActiveConnections = 64 - ) - db = PostgreSQLConnectionBuilder.createConnectionPool(dbConfig).asSuspending + companion object { + const val WORLD_QUERY = "select id, randomNumber from world where id = ?" + const val FORTUNES_QUERY = "select id, message from fortune" + const val UPDATE_QUERY = "update world set randomNumber = ? where id = ?" } + private val dbConfig: ConnectionPoolConfiguration = ConnectionPoolConfiguration( + "tfb-database", + database = "hello_world", + username = "benchmarkdbuser", + password = "benchmarkdbpass", + maxActiveConnections = 64 + ) + private val db: SuspendingConnection = PostgreSQLConnectionBuilder.createConnectionPool(dbConfig).asSuspending + override suspend fun getWorld(): World { val worldId = rand.nextInt(1, 10000) - val result = db.sendPreparedStatement("select id, randomNumber from world where id = ?", listOf(worldId)) + val result = db.sendPreparedStatement(WORLD_QUERY, listOf(worldId)) val row = result.rows.first() return World(row.getInt(0)!!, row.getInt(1)!!) } override suspend fun getFortunes(): List { - val results = db.sendPreparedStatement("select id, message from fortune") + val results = db.sendPreparedStatement(FORTUNES_QUERY) return results.rows.map { Fortune(it.getInt(0)!!, it.getString(1)!!) } } override suspend fun updateWorlds(worlds: List) { - worlds.forEach { world -> - db.sendPreparedStatement( - "update world set randomNumber = ? where id = ?", - listOf(world.randomNumber, world.id) - ) - } - } -} + coroutineScope { + val jobs = ArrayList>(worlds.size) + worlds.forEach { world -> + val deferred = async(Dispatchers.IO) { + db.sendPreparedStatement( + UPDATE_QUERY, + listOf(world.randomNumber, world.id) + ) + } + jobs.add(deferred) + } -class ReactivePGRepository : Repository { - private val db: PgPool - - init { - val poolOptions = PgPoolOptions() - poolOptions.apply { - host = "tfb-database" - database = "hello_world" - user = "benchmarkdbuser" - password = "benchmarkdbpass" - maxSize = 64 - cachePreparedStatements = true + jobs.awaitAll() } - db = PgClient.pool(poolOptions) - } - - override suspend fun getFortunes(): List { - val results = db.preparedQueryAwait("select id, message from fortune") - return results.map { Fortune(it.getInteger(0), it.getString(1)) } - } - - override suspend fun getWorld(): World { - val worldId = rand.nextInt(1, 10000) - val result = db.preparedQueryAwait("select id, randomNumber from world where id = $1", Tuple.of(worldId)) - val row = result.first() - return World(row.getInteger(0), row.getInteger(1)!!) - } - - override suspend fun updateWorlds(worlds: List) { - val batch = worlds.map { Tuple.of(it.id, it.randomNumber) } - db.preparedBatchAwait("update world set randomNumber = $1 where id = $2", batch) } } @@ -132,7 +100,7 @@ class MainTemplate : Template { } } -class FortuneTemplate(val fortunes: List, val main: MainTemplate = MainTemplate()) : Template { +class FortuneTemplate(private val fortunes: List, private val main: MainTemplate = MainTemplate()) : Template { override fun HTML.apply() { insert(main) { content { @@ -156,13 +124,9 @@ class FortuneTemplate(val fortunes: List, val main: MainTemplate = Main fun main(args: Array) { val db = when(args.firstOrNull()) { "jasync-sql" -> JasyncRepository() - "reactive-pg" -> ReactivePGRepository() else -> throw IllegalArgumentException("Must specify a postgres client") } - val messageSerializer = Message.serializer() - val worldSerializer = World.serializer() - val server = embeddedServer(Netty, 8080, configure = { shareWorkGroup = true }) { @@ -174,19 +138,19 @@ fun main(args: Array) { get("/json") { call.respondText( - JSON.stringify(messageSerializer, Message("Hello, World!")), + Json.encodeToString(Message("Hello, World!")), ContentType.Application.Json ) } get("/db") { - call.respondText(JSON.stringify(worldSerializer, db.getWorld()), ContentType.Application.Json) + call.respondText(Json.encodeToString(db.getWorld()), ContentType.Application.Json) } get("/query/") { val queries = call.parameters["queries"]?.toBoxedInt(1..500) ?: 1 val worlds = (1..queries).map { db.getWorld() } - call.respondText(JSON.stringify(worldSerializer.list, worlds), ContentType.Application.Json) + call.respondText(Json.encodeToString(worlds), ContentType.Application.Json) } get("/fortunes") { @@ -204,7 +168,7 @@ fun main(args: Array) { db.updateWorlds(newWorlds) - call.respondText(JSON.stringify(worldSerializer.list, newWorlds), ContentType.Application.Json) + call.respondText(Json.encodeToString(newWorlds), ContentType.Application.Json) } } } diff --git a/frameworks/Kotlin/ktor/ktor-cio.dockerfile b/frameworks/Kotlin/ktor/ktor-cio.dockerfile index 6ba40b6eccc..33059ec9fd4 100644 --- a/frameworks/Kotlin/ktor/ktor-cio.dockerfile +++ b/frameworks/Kotlin/ktor/ktor-cio.dockerfile @@ -1,10 +1,10 @@ -FROM maven:3.6.1-jdk-11-slim as maven +FROM maven:3.9.7-amazoncorretto-17-debian as maven WORKDIR /ktor COPY ktor/pom.xml pom.xml COPY ktor/src src RUN mvn clean package -q -FROM openjdk:11.0.3-jdk-stretch +FROM amazoncorretto:17.0.11-al2023-headless WORKDIR /ktor COPY --from=maven /ktor/target/tech-empower-framework-benchmark-1.0-SNAPSHOT-cio-bundle.jar app.jar diff --git a/frameworks/Kotlin/ktor/ktor-exposed-dao.dockerfile b/frameworks/Kotlin/ktor/ktor-exposed-dao.dockerfile index 9867cf2931c..e12a664f8dc 100644 --- a/frameworks/Kotlin/ktor/ktor-exposed-dao.dockerfile +++ b/frameworks/Kotlin/ktor/ktor-exposed-dao.dockerfile @@ -1,4 +1,4 @@ -FROM gradle:8.0.2-jdk11 +FROM gradle:jdk17 WORKDIR /ktor-exposed COPY ktor-exposed/settings.gradle.kts settings.gradle.kts diff --git a/frameworks/Kotlin/ktor/ktor-exposed-dsl.dockerfile b/frameworks/Kotlin/ktor/ktor-exposed-dsl.dockerfile index 5b7f7fe722a..f65069e6b78 100644 --- a/frameworks/Kotlin/ktor/ktor-exposed-dsl.dockerfile +++ b/frameworks/Kotlin/ktor/ktor-exposed-dsl.dockerfile @@ -1,4 +1,4 @@ -FROM gradle:8.0.2-jdk11 +FROM gradle:jdk17 WORKDIR /ktor-exposed COPY ktor-exposed/settings.gradle.kts settings.gradle.kts diff --git a/frameworks/Kotlin/ktor/ktor-exposed/app/build.gradle.kts b/frameworks/Kotlin/ktor/ktor-exposed/app/build.gradle.kts index 4d798b53bcf..60f4dab3b17 100644 --- a/frameworks/Kotlin/ktor/ktor-exposed/app/build.gradle.kts +++ b/frameworks/Kotlin/ktor/ktor-exposed/app/build.gradle.kts @@ -1,7 +1,7 @@ plugins { - kotlin("jvm") version "1.8.10" - kotlin("plugin.serialization") version "1.8.10" application + kotlin("jvm") version "1.9.22" + kotlin("plugin.serialization") version "2.0.0" id("com.github.johnrengelman.shadow") version "8.1.0" } @@ -9,9 +9,9 @@ repositories { mavenCentral() } -val ktorVersion = "2.2.3" -val kotlinxSerializationVersion = "1.5.0" -val exposedVersion = "0.41.1" +val ktorVersion = "2.3.12" +val kotlinxSerializationVersion = "1.6.3" +val exposedVersion = "0.52.0" dependencies { implementation("io.ktor:ktor-server-core:$ktorVersion") diff --git a/frameworks/Kotlin/ktor/ktor-jasync.dockerfile b/frameworks/Kotlin/ktor/ktor-jasync.dockerfile index 38649f62693..8c66e81ea4e 100644 --- a/frameworks/Kotlin/ktor/ktor-jasync.dockerfile +++ b/frameworks/Kotlin/ktor/ktor-jasync.dockerfile @@ -1,7 +1,7 @@ -FROM openjdk:11.0.3-jdk-stretch +FROM maven:3.9.7-amazoncorretto-17-debian WORKDIR /app COPY ktor-asyncdb/gradle gradle -COPY ktor-asyncdb/build.gradle build.gradle +COPY ktor-asyncdb/build.gradle.kts build.gradle.kts COPY ktor-asyncdb/gradle.properties gradle.properties COPY ktor-asyncdb/gradlew gradlew COPY ktor-asyncdb/settings.gradle settings.gradle diff --git a/frameworks/Kotlin/ktor/ktor-jetty.dockerfile b/frameworks/Kotlin/ktor/ktor-jetty.dockerfile index 3976e5f2df9..e753d7cc442 100644 --- a/frameworks/Kotlin/ktor/ktor-jetty.dockerfile +++ b/frameworks/Kotlin/ktor/ktor-jetty.dockerfile @@ -1,10 +1,10 @@ -FROM maven:3.6.1-jdk-11-slim as maven +FROM maven:3.9.7-amazoncorretto-17-debian as maven WORKDIR /ktor COPY ktor/pom.xml pom.xml COPY ktor/src src RUN mvn clean package -q -FROM openjdk:11.0.3-jdk-stretch +FROM amazoncorretto:17.0.11-al2023-headless WORKDIR /ktor COPY --from=maven /ktor/target/tech-empower-framework-benchmark-1.0-SNAPSHOT-jetty-bundle.jar app.jar diff --git a/frameworks/Kotlin/ktor/ktor-pgclient.dockerfile b/frameworks/Kotlin/ktor/ktor-pgclient.dockerfile index be123f07e6f..0cf012e7596 100644 --- a/frameworks/Kotlin/ktor/ktor-pgclient.dockerfile +++ b/frameworks/Kotlin/ktor/ktor-pgclient.dockerfile @@ -1,4 +1,4 @@ -FROM openjdk:11.0.3-jdk-stretch as build +FROM maven:3.9.7-amazoncorretto-17-debian as build WORKDIR /app COPY ktor-pgclient/gradle gradle COPY ktor-pgclient/build.gradle.kts build.gradle.kts @@ -6,7 +6,7 @@ COPY ktor-pgclient/gradlew gradlew COPY ktor-pgclient/src src RUN /app/gradlew --no-daemon shadowJar -FROM openjdk:11.0.3-jdk-slim +FROM amazoncorretto:17.0.11-al2023-headless WORKDIR /app COPY --from=build /app/build/libs/ktor-pgclient.jar ktor-pgclient.jar diff --git a/frameworks/Kotlin/ktor/ktor-pgclient/build.gradle.kts b/frameworks/Kotlin/ktor/ktor-pgclient/build.gradle.kts index f57c372b49f..f080b64d69f 100644 --- a/frameworks/Kotlin/ktor/ktor-pgclient/build.gradle.kts +++ b/frameworks/Kotlin/ktor/ktor-pgclient/build.gradle.kts @@ -1,8 +1,8 @@ plugins { application - kotlin("jvm") version "1.6.10" - id("org.jetbrains.kotlin.plugin.serialization") version "1.6.21" - id("com.github.johnrengelman.shadow") version "7.1.2" + kotlin("jvm") version "1.9.22" + kotlin("plugin.serialization") version "2.0.0" + id("com.github.johnrengelman.shadow") version "8.1.0" } group = "org.jetbrains.ktor" @@ -16,19 +16,20 @@ application { mainClass.set("MainKt") } +val ktor_version = "2.3.12" + dependencies { - implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8") - implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.3.2") - implementation("io.ktor:ktor-server-netty:2.0.1") - implementation("io.ktor:ktor-server-html-builder-jvm:2.0.1") - implementation("io.ktor:ktor-server-default-headers-jvm:2.0.1") - implementation("io.vertx:vertx-pg-client:4.2.3") - implementation("io.vertx:vertx-lang-kotlin:4.2.3") - implementation("io.vertx:vertx-lang-kotlin-coroutines:4.2.3") + implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.3") + implementation("io.ktor:ktor-server-netty:$ktor_version") + implementation("io.ktor:ktor-server-html-builder-jvm:$ktor_version") + implementation("io.ktor:ktor-server-default-headers-jvm:$ktor_version") + implementation("io.vertx:vertx-pg-client:4.5.8") + implementation("io.vertx:vertx-lang-kotlin:4.5.8") + implementation("io.vertx:vertx-lang-kotlin-coroutines:4.5.8") } tasks.withType().configureEach { - kotlinOptions.jvmTarget = "11" + kotlinOptions.jvmTarget = "17" } tasks.shadowJar { diff --git a/frameworks/Kotlin/ktor/ktor-pgclient/gradle/wrapper/gradle-wrapper.properties b/frameworks/Kotlin/ktor/ktor-pgclient/gradle/wrapper/gradle-wrapper.properties index aa991fceae6..e1bef7e873c 100644 --- a/frameworks/Kotlin/ktor/ktor-pgclient/gradle/wrapper/gradle-wrapper.properties +++ b/frameworks/Kotlin/ktor/ktor-pgclient/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.2-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.0.2-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/frameworks/Kotlin/ktor/ktor-pgclient/src/main/kotlin/main.kt b/frameworks/Kotlin/ktor/ktor-pgclient/src/main/kotlin/main.kt index b4f7dc89615..c8e74244f99 100644 --- a/frameworks/Kotlin/ktor/ktor-pgclient/src/main/kotlin/main.kt +++ b/frameworks/Kotlin/ktor/ktor-pgclient/src/main/kotlin/main.kt @@ -7,6 +7,8 @@ import io.ktor.server.plugins.defaultheaders.* import io.ktor.server.response.* import io.ktor.server.routing.* import io.vertx.kotlin.coroutines.await +import io.vertx.kotlin.coroutines.coAwait +import io.vertx.pgclient.PgBuilder import io.vertx.pgclient.PgConnectOptions import io.vertx.pgclient.PgPool import io.vertx.sqlclient.PoolOptions @@ -35,6 +37,12 @@ interface Repository { } class PgclientRepository : Repository { + companion object { + private const val FORTUNES_QUERY = "select id, message from FORTUNE" + private const val SELECT_WORLD_QUERY = "SELECT id, randomnumber from WORLD where id=$1" + private const val UPDATE_WORLD_QUERY = "UPDATE WORLD SET randomnumber=$1 WHERE id=$2" + } + private val connectOptions = PgConnectOptions().apply { port = 5432 @@ -47,21 +55,23 @@ class PgclientRepository : Repository { } private val poolOptions = PoolOptions() - private val client = ThreadLocal.withInitial { PgPool.client(connectOptions, poolOptions) } - private fun client() = client.get() + private val client = PgBuilder.client() + .with(poolOptions) + .connectingTo(connectOptions) + .build() override suspend fun getFortunes(): List { - val results = client().preparedQuery("select id, message from fortune").execute().await() + val results = client.preparedQuery(FORTUNES_QUERY).execute().coAwait() return results.map { Fortune(it.getInteger(0), it.getString(1)) } } override suspend fun getWorld(): World { val worldId = rand.nextInt(1, 10001) val result = - client() - .preparedQuery("select id, randomNumber from world where id = $1") + client + .preparedQuery(SELECT_WORLD_QUERY) .execute(Tuple.of(worldId)) - .await() + .coAwait() val row = result.first() return World(row.getInteger(0), row.getInteger(1)!!) } @@ -69,10 +79,10 @@ class PgclientRepository : Repository { override suspend fun updateWorlds(worlds: List) { // Worlds should be sorted before being batch-updated with to avoid data race and deadlocks. val batch = worlds.sortedBy { it.id }.map { Tuple.of(it.randomNumber, it.id) } - client() - .preparedQuery("update world set randomNumber = $1 where id = $2") + client + .preparedQuery(UPDATE_WORLD_QUERY) .executeBatch(batch) - .await() + .coAwait() } } diff --git a/frameworks/Kotlin/ktor/ktor-reactivepg.dockerfile b/frameworks/Kotlin/ktor/ktor-reactivepg.dockerfile deleted file mode 100644 index 41476da82ba..00000000000 --- a/frameworks/Kotlin/ktor/ktor-reactivepg.dockerfile +++ /dev/null @@ -1,13 +0,0 @@ -FROM openjdk:11.0.3-jdk-stretch -WORKDIR /app -COPY ktor-asyncdb/gradle gradle -COPY ktor-asyncdb/build.gradle build.gradle -COPY ktor-asyncdb/gradle.properties gradle.properties -COPY ktor-asyncdb/gradlew gradlew -COPY ktor-asyncdb/settings.gradle settings.gradle -COPY ktor-asyncdb/src src -RUN /app/gradlew --no-daemon shadowJar - -EXPOSE 9090 - -CMD ["java", "-server", "-XX:+UseParallelGC", "-Xms2G","-Xmx2G", "-jar", "/app/build/libs/bench.jar", "reactive-pg"] diff --git a/frameworks/Kotlin/ktor/ktor.dockerfile b/frameworks/Kotlin/ktor/ktor.dockerfile index 36aa32fd8c2..1558d312736 100644 --- a/frameworks/Kotlin/ktor/ktor.dockerfile +++ b/frameworks/Kotlin/ktor/ktor.dockerfile @@ -1,13 +1,13 @@ -FROM maven:3.6.1-jdk-11-slim as maven +FROM maven:3.9.7-amazoncorretto-17-debian as maven WORKDIR /ktor COPY ktor/pom.xml pom.xml COPY ktor/src src RUN mvn clean package -q -FROM openjdk:11.0.3-jdk-stretch +FROM amazoncorretto:17.0.11-al2023-headless WORKDIR /ktor COPY --from=maven /ktor/target/tech-empower-framework-benchmark-1.0-SNAPSHOT-netty-bundle.jar app.jar EXPOSE 9090 -CMD ["java", "-server","-XX:+UseNUMA", "-XX:+UseParallelGC", "-XX:+AggressiveOpts", "-XX:+AlwaysPreTouch", "-jar", "app.jar"] +CMD ["java", "-server","-XX:+UseNUMA", "-XX:+UseParallelGC", "-XX:+AlwaysPreTouch", "-jar", "app.jar"] diff --git a/frameworks/Kotlin/ktor/ktor/README.md b/frameworks/Kotlin/ktor/ktor/README.md index 07cb92359c2..e3c141a70e0 100644 --- a/frameworks/Kotlin/ktor/ktor/README.md +++ b/frameworks/Kotlin/ktor/ktor/README.md @@ -5,13 +5,13 @@ More information is available at [ktor.io](http://ktor.io). # Setup -* Java 8 +* Java 17 * MySQL server # Requirements * Maven 3 -* JDK 8 +* JDK 17 * Kotlin * ktor * netty diff --git a/frameworks/Kotlin/ktor/ktor/pom.xml b/frameworks/Kotlin/ktor/ktor/pom.xml index 35ad4547a16..a794bb59fe3 100644 --- a/frameworks/Kotlin/ktor/ktor/pom.xml +++ b/frameworks/Kotlin/ktor/ktor/pom.xml @@ -12,10 +12,10 @@ org.jetbrains.ktor tech-empower-framework-benchmark - 1.6.21 - 2.0.1 - 1.3.2 - 0.7.3 + 1.9.22 + 2.3.11 + 1.6.3 + 0.11.0 UTF-8 5.0.0 1.2.13 @@ -24,11 +24,6 @@ - - org.jetbrains.kotlin - kotlin-stdlib-jdk8 - ${kotlin.version} - org.jetbrains.kotlin kotlin-reflect @@ -85,17 +80,17 @@ io.ktor ktor-server-netty-jvm - 2.0.0 + ${ktor.version} io.ktor ktor-server-jetty-jvm - 2.0.0 + ${ktor.version} io.ktor ktor-server-cio-jvm - 2.0.0 + ${ktor.version} diff --git a/frameworks/Kotlin/ktor/ktor/src/main/kotlin/org/jetbrains/ktor/benchmarks/Hello.kt b/frameworks/Kotlin/ktor/ktor/src/main/kotlin/org/jetbrains/ktor/benchmarks/Hello.kt index b767e0605f5..82bdd34bc66 100644 --- a/frameworks/Kotlin/ktor/ktor/src/main/kotlin/org/jetbrains/ktor/benchmarks/Hello.kt +++ b/frameworks/Kotlin/ktor/ktor/src/main/kotlin/org/jetbrains/ktor/benchmarks/Hello.kt @@ -9,12 +9,14 @@ import io.ktor.server.html.* import io.ktor.server.plugins.defaultheaders.* import io.ktor.server.response.* import io.ktor.server.routing.* -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.withContext +import kotlinx.coroutines.* import kotlinx.html.* import kotlinx.serialization.Serializable import kotlinx.serialization.encodeToString import kotlinx.serialization.json.Json +import org.jetbrains.ktor.benchmarks.Constants.FORTUNES_QUERY +import org.jetbrains.ktor.benchmarks.Constants.UPDATE_QUERY +import org.jetbrains.ktor.benchmarks.Constants.WORLD_QUERY import java.sql.Connection import java.util.concurrent.ThreadLocalRandom @@ -30,7 +32,7 @@ data class Fortune(val id: Int, var message: String) fun Application.main() { val dbRows = 10000 val poolSize = 48 - val pool by lazy { HikariDataSource(HikariConfig().apply { configurePostgres(poolSize) }) } + val pool = HikariDataSource(HikariConfig().apply { configurePostgres(poolSize) }) val databaseDispatcher = Dispatchers.IO install(DefaultHeaders) @@ -51,7 +53,7 @@ fun Application.main() { val world = withContext(databaseDispatcher) { pool.connection.use { connection -> - connection.prepareStatement("SELECT id, randomNumber FROM World WHERE id = ?").use { statement -> + connection.prepareStatement(WORLD_QUERY).use { statement -> statement.setInt(1, random.nextInt(dbRows) + 1) statement.executeQuery().use { rs -> @@ -67,7 +69,7 @@ fun Application.main() { fun Connection.selectWorlds(queries: Int, random: ThreadLocalRandom): List { val result = ArrayList(queries) - prepareStatement("SELECT id, randomNumber FROM World WHERE id = ?").use { statement -> + prepareStatement(WORLD_QUERY).use { statement -> repeat(queries) { statement.setInt(1, random.nextInt(dbRows) + 1) @@ -96,7 +98,7 @@ fun Application.main() { val result = mutableListOf() withContext(databaseDispatcher) { pool.connection.use { connection -> - connection.prepareStatement("SELECT id, message FROM fortune").use { statement -> + connection.prepareStatement(FORTUNES_QUERY).use { statement -> statement.executeQuery().use { rs -> while (rs.next()) { result += Fortune(rs.getInt(1), rs.getString(2)) @@ -137,7 +139,7 @@ fun Application.main() { result.forEach { it.randomNumber = random.nextInt(dbRows) + 1 } - connection.prepareStatement("UPDATE World SET randomNumber = ? WHERE id = ?") + connection.prepareStatement(UPDATE_QUERY) .use { updateStatement -> for ((id, randomNumber) in result) { updateStatement.setInt(1, randomNumber) @@ -182,3 +184,10 @@ fun HikariConfig.configureMySql(poolSize: Int) { fun ApplicationCall.queries() = request.queryParameters["queries"]?.toIntOrNull()?.coerceIn(1, 500) ?: 1 + + +object Constants { + const val WORLD_QUERY = "SELECT id, randomNumber FROM World WHERE id = ?" + const val FORTUNES_QUERY = "SELECT id, message FROM fortune" + const val UPDATE_QUERY = "UPDATE World SET randomNumber = ? WHERE id = ?" +} \ No newline at end of file From 9ab75acf9c341630cfeae907f2f3b2c3d70930cf Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 22 Jul 2024 18:11:29 +0000 Subject: [PATCH 040/204] Bump openssl from 0.10.61 to 0.10.66 in /frameworks/Rust/axum Bumps [openssl](https://github.com/sfackler/rust-openssl) from 0.10.61 to 0.10.66. - [Release notes](https://github.com/sfackler/rust-openssl/releases) - [Commits](https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.61...openssl-v0.10.66) --- updated-dependencies: - dependency-name: openssl dependency-type: indirect ... Signed-off-by: dependabot[bot] --- frameworks/Rust/axum/Cargo.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/frameworks/Rust/axum/Cargo.lock b/frameworks/Rust/axum/Cargo.lock index 3d63ad71fb7..3a9dba5fb18 100644 --- a/frameworks/Rust/axum/Cargo.lock +++ b/frameworks/Rust/axum/Cargo.lock @@ -1379,9 +1379,9 @@ checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" [[package]] name = "openssl" -version = "0.10.61" +version = "0.10.66" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b8419dc8cc6d866deb801274bba2e6f8f6108c1bb7fcc10ee5ab864931dbb45" +checksum = "9529f4786b70a3e8c61e11179af17ab6188ad8d0ded78c5529441ed39d4bd9c1" dependencies = [ "bitflags 2.4.1", "cfg-if", @@ -1411,9 +1411,9 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" [[package]] name = "openssl-sys" -version = "0.9.97" +version = "0.9.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3eaad34cdd97d81de97964fc7f29e2d104f483840d906ef56daa1912338460b" +checksum = "7f9e8deee91df40a943c71b917e5874b951d32a802526c85721ce3b776c929d6" dependencies = [ "cc", "libc", From 7e12fbc94fff02c257fd18a824c563cf9e51bd3d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 22 Jul 2024 18:41:22 +0000 Subject: [PATCH 041/204] Bump io.undertow:undertow-core in /frameworks/Java/light-java Bumps [io.undertow:undertow-core](https://github.com/undertow-io/undertow) from 2.3.12.Final to 2.3.15.Final. - [Release notes](https://github.com/undertow-io/undertow/releases) - [Commits](https://github.com/undertow-io/undertow/compare/2.3.12.Final...2.3.15.Final) --- updated-dependencies: - dependency-name: io.undertow:undertow-core dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- frameworks/Java/light-java/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frameworks/Java/light-java/pom.xml b/frameworks/Java/light-java/pom.xml index 0d76eb4e631..787dc1253bb 100644 --- a/frameworks/Java/light-java/pom.xml +++ b/frameworks/Java/light-java/pom.xml @@ -25,7 +25,7 @@ 11 2.0.1 1.3.12 - 2.3.12.Final + 2.3.15.Final 3.3.1 8.0.28 42.7.2 From 8710bc806824912856ece4650e415009b30f91f3 Mon Sep 17 00:00:00 2001 From: Vladimir Shchur Date: Tue, 23 Jul 2024 20:44:30 +0300 Subject: [PATCH 042/204] [F#/Oxpecker] Several improvements (#9170) * [F#/Oxpecker] Change fortunes serialization to chunked * [F#/Oxpecker] Database query improvements * [F#/Oxpecker] Disabled config file changes --- .../FSharp/oxpecker/oxpecker.dockerfile | 1 + frameworks/FSharp/oxpecker/src/App/App.fsproj | 2 +- frameworks/FSharp/oxpecker/src/App/Db.fs | 23 +++++++++++++------ frameworks/FSharp/oxpecker/src/App/Program.fs | 2 +- 4 files changed, 19 insertions(+), 9 deletions(-) diff --git a/frameworks/FSharp/oxpecker/oxpecker.dockerfile b/frameworks/FSharp/oxpecker/oxpecker.dockerfile index 35a8c509c96..4f6676892c3 100644 --- a/frameworks/FSharp/oxpecker/oxpecker.dockerfile +++ b/frameworks/FSharp/oxpecker/oxpecker.dockerfile @@ -6,6 +6,7 @@ RUN dotnet publish -c Release -o out FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS runtime ENV DOTNET_ReadyToRun 0 +ENV ASPNETCORE_hostBuilder__reloadConfigOnChange false ENV URLS http://+:8080 diff --git a/frameworks/FSharp/oxpecker/src/App/App.fsproj b/frameworks/FSharp/oxpecker/src/App/App.fsproj index f01c367f95f..1b6f8b76cd3 100644 --- a/frameworks/FSharp/oxpecker/src/App/App.fsproj +++ b/frameworks/FSharp/oxpecker/src/App/App.fsproj @@ -13,7 +13,7 @@ - + \ No newline at end of file diff --git a/frameworks/FSharp/oxpecker/src/App/Db.fs b/frameworks/FSharp/oxpecker/src/App/Db.fs index 498721b2b2e..2c471bada1d 100644 --- a/frameworks/FSharp/oxpecker/src/App/Db.fs +++ b/frameworks/FSharp/oxpecker/src/App/Db.fs @@ -21,19 +21,19 @@ module Db = return result } - let private createReadCommand (connection: DbConnection) = + let private createReadCommand (connection: NpgsqlConnection) = let cmd = connection.CreateCommand( CommandText = "SELECT id, randomnumber FROM world WHERE id = @Id" ) - let id = cmd.CreateParameter( + let id = NpgsqlParameter( ParameterName = "@Id", DbType = DbType.Int32, - Value = Random.Shared.Next(1, 10001) + TypedValue = Random.Shared.Next(1, 10001) ) cmd.Parameters.Add(id) |> ignore cmd - let private readSingleRow (cmd: DbCommand) = + let private readSingleRow (cmd: NpgsqlCommand) = task { use! rdr = cmd.ExecuteReaderAsync(CommandBehavior.SingleRow) let! _ = rdr.ReadAsync() @@ -83,12 +83,21 @@ module Db = | q -> q - let private generateParameters (results: World[]) (command: DbCommand) = + // fill cache + let _ = [| 0..maxBatch |] |> Array.map batchUpdateString + + let private paramNames = + seq { 0..maxBatch*2 } + |> Seq.map (fun i -> struct($"@Rn_{i}", $"@Id_{i}")) + |> Seq.toArray + + let private generateParameters (results: World[]) (command: NpgsqlCommand) = for i in 0..results.Length-1 do let randomNumber = Random.Shared.Next(1, 10001) - let random = command.CreateParameter(ParameterName = $"@Rn_{i}", DbType = DbType.Int32, Value = randomNumber) + let struct(rnParamName, idParamName) = paramNames[i] + let random = NpgsqlParameter(ParameterName = rnParamName, DbType = DbType.Int32, TypedValue = randomNumber) command.Parameters.Add(random) |> ignore - let id = command.CreateParameter(ParameterName = $"@Id_{i}", DbType = DbType.Int32, Value = results[i].id) + let id = NpgsqlParameter(ParameterName = idParamName, DbType = DbType.Int32, TypedValue = results[i].id) command.Parameters.Add(id) |> ignore results[i] <- { results[i] with randomnumber = randomNumber } diff --git a/frameworks/FSharp/oxpecker/src/App/Program.fs b/frameworks/FSharp/oxpecker/src/App/Program.fs index dcfd3c53206..09ba84b4fae 100644 --- a/frameworks/FSharp/oxpecker/src/App/Program.fs +++ b/frameworks/FSharp/oxpecker/src/App/Program.fs @@ -49,7 +49,7 @@ module HttpHandlers = let rec private renderFortunes (ctx: HttpContext) (data: ResizeArray) = data.Add extra data.Sort FortuneComparer - data |> HtmlViews.fortunes |> ctx.WriteHtmlView + data |> HtmlViews.fortunes |> ctx.WriteHtmlViewChunked let fortunes : EndpointHandler = fun ctx -> From 1a62761218245423a85fc42794588de29ad3638e Mon Sep 17 00:00:00 2001 From: Julien Viet Date: Tue, 23 Jul 2024 19:45:09 +0200 Subject: [PATCH 043/204] Upgrade to Vert.x 4.5.9 and use the new data object JSON serializer library, in addition perform a few tweaks to the server. (#9171) --- frameworks/Java/vertx/pom.xml | 19 +- .../Java/vertx/src/main/java/vertx/App.java | 252 +++++++++--------- .../main/java/vertx/model/CachedWorld.java | 15 +- .../src/main/java/vertx/model/Fortune.java | 17 +- .../src/main/java/vertx/model/Message.java | 23 +- .../src/main/java/vertx/model/World.java | 19 +- .../main/java/vertx/model/package-info.java | 4 + .../Java/vertx/vertx-postgres.dockerfile | 1 + frameworks/Java/vertx/vertx.dockerfile | 2 +- 9 files changed, 194 insertions(+), 158 deletions(-) create mode 100644 frameworks/Java/vertx/src/main/java/vertx/model/package-info.java diff --git a/frameworks/Java/vertx/pom.xml b/frameworks/Java/vertx/pom.xml index cdb3aa09f6a..12eff9d69a5 100644 --- a/frameworks/Java/vertx/pom.xml +++ b/frameworks/Java/vertx/pom.xml @@ -10,9 +10,9 @@ 17 vertx.App - 4.5.8 + 4.5.9 2.16.1 - 4.1.110.Final + 4.1.111.Final 0.0.25.Final @@ -32,6 +32,11 @@ jackson-core ${jackson.version} + + com.julienviet + jsonsergen + 0.0.4 + io.netty netty-transport-native-kqueue @@ -70,6 +75,16 @@ false + + + default-compile + + + io.vertx.codegen.CodeGenProcessor + + + + com.fizzed diff --git a/frameworks/Java/vertx/src/main/java/vertx/App.java b/frameworks/Java/vertx/src/main/java/vertx/App.java index 5e81292d8ed..5afa269ae9e 100755 --- a/frameworks/Java/vertx/src/main/java/vertx/App.java +++ b/frameworks/Java/vertx/src/main/java/vertx/App.java @@ -12,17 +12,12 @@ import io.vertx.core.http.HttpServerOptions; import io.vertx.core.http.HttpServerRequest; import io.vertx.core.http.HttpServerResponse; -import io.vertx.core.json.JsonArray; import io.vertx.core.json.JsonObject; import io.vertx.core.logging.Logger; import io.vertx.core.logging.LoggerFactory; import io.vertx.sqlclient.*; import io.vertx.sqlclient.impl.SqlClientInternal; -import vertx.model.CachedWorld; -import vertx.model.Fortune; -import vertx.model.Message; -import vertx.model.World; -import vertx.model.WorldCache; +import vertx.model.*; import vertx.rocker.BufferRockerOutput; import java.io.ByteArrayOutputStream; @@ -38,9 +33,13 @@ import java.util.List; import java.util.concurrent.ThreadLocalRandom; import java.util.stream.Collectors; +import java.util.stream.IntStream; public class App extends AbstractVerticle implements Handler { + private static final int NUM_PROCESSORS = Runtime.getRuntime().availableProcessors(); + private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(App.class); + /** * Returns the value of the "queries" getRequest parameter, which is an integer * bound between 1 and 500 with a default value of 1. @@ -62,7 +61,9 @@ static int getQueries(HttpServerRequest request) { } } - static Logger logger = LoggerFactory.getLogger(App.class.getName()); + private static Logger logger = LoggerFactory.getLogger(App.class.getName()); + + private static final Integer[] BOXED_RND = IntStream.range(1, 10001).boxed().toArray(Integer[]::new); private static final String PATH_PLAINTEXT = "/plaintext"; private static final String PATH_JSON = "/json"; @@ -76,7 +77,7 @@ static int getQueries(HttpServerRequest request) { private static final CharSequence RESPONSE_TYPE_PLAIN = HttpHeaders.createOptimized("text/plain"); private static final CharSequence RESPONSE_TYPE_HTML = HttpHeaders.createOptimized("text/html; charset=UTF-8"); - private static final CharSequence RESPONSE_TYPE_JSON = HttpHeaders.createOptimized("application/json"); + static final CharSequence RESPONSE_TYPE_JSON = HttpHeaders.createOptimized("application/json"); private static final String HELLO_WORLD = "Hello, world!"; private static final Buffer HELLO_WORLD_BUFFER = Buffer.buffer(HELLO_WORLD, "UTF-8"); @@ -89,14 +90,29 @@ static int getQueries(HttpServerRequest request) { private static final CharSequence HELLO_WORLD_LENGTH = HttpHeaders.createOptimized("" + HELLO_WORLD.length()); private static final CharSequence SERVER = HttpHeaders.createOptimized("vert.x"); - private static final String UPDATE_WORLD = "UPDATE world SET randomnumber=$1 WHERE id=$2"; private static final String SELECT_WORLD = "SELECT id, randomnumber from WORLD where id=$1"; private static final String SELECT_FORTUNE = "SELECT id, message from FORTUNE"; private static final String SELECT_WORLDS = "SELECT id, randomnumber from WORLD"; + public static CharSequence createDateHeader() { + return HttpHeaders.createOptimized(DateTimeFormatter.RFC_1123_DATE_TIME.format(ZonedDateTime.now())); + } + + /** + * Returns a random integer that is a suitable value for both the {@code id} + * and {@code randomNumber} properties of a world object. + * + * @return a random world number + */ + static Integer boxedRandomWorldNumber() { + final int rndValue = ThreadLocalRandom.current().nextInt(1, 10001); + final var boxedRnd = BOXED_RND[rndValue - 1]; + assert boxedRnd.intValue() == rndValue; + return boxedRnd; + } + private HttpServer server; - private SqlClientInternal client1; - private SqlClientInternal client2; + private SqlClientInternal client; private CharSequence dateString; private CharSequence[] plaintextHeaders; @@ -105,15 +121,10 @@ static int getQueries(HttpServerRequest request) { private Throwable databaseErr; private PreparedQuery> SELECT_WORLD_QUERY; private PreparedQuery>> SELECT_FORTUNE_QUERY; - private PreparedQuery> UPDATE_WORLD_QUERY; @SuppressWarnings("unchecked") - private PreparedQuery>[] AGGREGATED_UPDATE_WORLD_QUERY = new PreparedQuery[128]; + private PreparedQuery>[] AGGREGATED_UPDATE_WORLD_QUERY = new PreparedQuery[500]; private WorldCache WORLD_CACHE; - public static CharSequence createDateHeader() { - return HttpHeaders.createOptimized(DateTimeFormatter.RFC_1123_DATE_TIME.format(ZonedDateTime.now())); - } - @Override public void start(Promise startPromise) throws Exception { int port = 8080; @@ -134,6 +145,7 @@ public void start(Promise startPromise) throws Exception { options.setUser(config.getString("username", "benchmarkdbuser")); options.setPassword(config.getString("password", "benchmarkdbpass")); options.setCachePreparedStatements(true); + options.setPreparedStatementCacheMaxSize(1024); options.setPipeliningLimit(100_000); // Large pipelining means less flushing and we use a single connection anyway Future clientsInit = initClients(options); clientsInit @@ -146,9 +158,9 @@ public void start(Promise startPromise) throws Exception { } private Future initClients(PgConnectOptions options) { - Future cf1 = PgConnection.connect(vertx, options) + return PgConnection.connect(vertx, options) .flatMap(conn -> { - client1 = (SqlClientInternal) conn; + client = (SqlClientInternal) conn; List> list = new ArrayList<>(); Future f1 = conn.prepare(SELECT_WORLD) .andThen(onSuccess(ps -> SELECT_WORLD_QUERY = ps.query())); @@ -165,15 +177,6 @@ private Future initClients(PgConnectOptions options) { .map(worlds -> new WorldCache(worlds.value())) .andThen(onSuccess(wc -> WORLD_CACHE = wc)); list.add(f3); - return Future.join(list); - }); - Future cf2 = PgConnection.connect(vertx, options) - .flatMap(conn -> { - client2 = (SqlClientInternal) conn; - List> list = new ArrayList<>(); - Future f1 = conn.prepare(UPDATE_WORLD) - .andThen(onSuccess(ps -> UPDATE_WORLD_QUERY = ps.query())); - list.add(f1); for (int i = 0; i < AGGREGATED_UPDATE_WORLD_QUERY.length; i++) { int idx = i; Future fut = conn @@ -183,22 +186,26 @@ private Future initClients(PgConnectOptions options) { } return Future.join(list); }); - return Future.join(cf1, cf2); } private static String buildAggregatedUpdateQuery(int len) { - StringBuilder sb = new StringBuilder(); - sb.append("UPDATE world SET randomNumber = update_data.randomNumber FROM (VALUES"); - char sep = ' '; - for (int i = 1;i <= len;i++) { - sb.append(sep).append("($").append(2 * i - 1).append("::int,$").append(2 * i).append("::int)"); - sep = ','; + StringBuilder sql = new StringBuilder(); + sql.append("UPDATE WORLD SET RANDOMNUMBER = CASE ID"); + for (int i = 0; i < len; i++) { + int offset = (i * 2) + 1; + sql.append(" WHEN $").append(offset).append(" THEN $").append(offset + 1); } - sb.append(") AS update_data (id, randomNumber) WHERE world.id = update_data.id"); - return sb.toString(); + sql.append(" ELSE RANDOMNUMBER"); + sql.append(" END WHERE ID IN ($1"); + for (int i = 1; i < len; i++) { + int offset = (i * 2) + 1; + sql.append(",$").append(offset); + } + sql.append(")"); + return sql.toString(); } - private static Handler> onSuccess(Handler handler) { + public static Handler> onSuccess(Handler handler) { return ar -> { if (ar.succeeded()) { handler.handle(ar.result()); @@ -232,8 +239,9 @@ public void handle(HttpServerRequest request) { handleCaching(request); break; default: - request.response().setStatusCode(404); - request.response().end(); + request.response() + .setStatusCode(404) + .end(); break; } } catch (Exception e) { @@ -267,22 +275,12 @@ private void handleJson(HttpServerRequest request) { .add(HEADER_CONTENT_TYPE, RESPONSE_TYPE_JSON) .add(HEADER_SERVER, SERVER) .add(HEADER_DATE, dateString); - response.end(new Message("Hello, World!").toBuffer(), NULL_HANDLER); - } - - /** - * Returns a random integer that is a suitable value for both the {@code id} - * and {@code randomNumber} properties of a world object. - * - * @return a random world number - */ - private static int randomWorld() { - return 1 + ThreadLocalRandom.current().nextInt(10000); + response.end(new Message("Hello, World!").toJson(), NULL_HANDLER); } private void handleDb(HttpServerRequest req) { HttpServerResponse resp = req.response(); - SELECT_WORLD_QUERY.execute(Tuple.of(randomWorld()), res -> { + SELECT_WORLD_QUERY.execute(Tuple.of(boxedRandomWorldNumber()), res -> { if (res.succeeded()) { RowIterator resultSet = res.result().iterator(); if (!resultSet.hasNext()) { @@ -290,11 +288,12 @@ private void handleDb(HttpServerRequest req) { return; } Row row = resultSet.next(); - resp - .putHeader(HttpHeaders.SERVER, SERVER) - .putHeader(HttpHeaders.DATE, dateString) - .putHeader(HttpHeaders.CONTENT_TYPE, RESPONSE_TYPE_JSON) - .end(new World(row.getInteger(0), row.getInteger(1)).toBuffer(), NULL_HANDLER); + World word = new World(row.getInteger(0), row.getInteger(1)); + MultiMap headers = resp.headers(); + headers.add(HttpHeaders.SERVER, SERVER); + headers.add(HttpHeaders.DATE, dateString); + headers.add(HttpHeaders.CONTENT_TYPE, RESPONSE_TYPE_JSON); + resp.end(word.toJson(), NULL_HANDLER); } else { sendError(req, res.cause()); } @@ -304,10 +303,11 @@ private void handleDb(HttpServerRequest req) { class Queries implements Handler>> { boolean failed; - final JsonArray worlds; + final World[] worlds; final HttpServerRequest req; final HttpServerResponse resp; final int queries; + int worldsIndex; public Queries(HttpServerRequest req) { int queries = getQueries(req); @@ -315,13 +315,14 @@ public Queries(HttpServerRequest req) { this.req = req; this.resp = req.response(); this.queries = queries; - this.worlds = new JsonArray(new ArrayList<>(queries)); + this.worlds = new World[queries]; + this.worldsIndex = 0; } private void handle() { - client1.group(c -> { + client.group(c -> { for (int i = 0; i < queries; i++) { - c.preparedQuery(SELECT_WORLD).execute(Tuple.of(randomWorld()), this); + c.preparedQuery(SELECT_WORLD).execute(Tuple.of(boxedRandomWorldNumber()), this); } }); } @@ -337,50 +338,48 @@ public void handle(AsyncResult> ar) { // we need a final reference final Tuple row = ar.result().iterator().next(); - worlds.add(new JsonObject().put("id", row.getInteger(0)).put("randomNumber", row.getInteger(1))); + worlds[worldsIndex++] = new World(row.getInteger(0), row.getInteger(1)); // stop condition - if (worlds.size() == queries) { - resp - .putHeader(HttpHeaders.SERVER, SERVER) - .putHeader(HttpHeaders.DATE, dateString) - .putHeader(HttpHeaders.CONTENT_TYPE, RESPONSE_TYPE_JSON) - .end(worlds.toBuffer(), NULL_HANDLER); + if (worldsIndex == queries) { + MultiMap headers = resp.headers(); + headers.add(HttpHeaders.SERVER, SERVER); + headers.add(HttpHeaders.DATE, dateString); + headers.add(HttpHeaders.CONTENT_TYPE, RESPONSE_TYPE_JSON); + resp.end(World.toJson(worlds), NULL_HANDLER); } } } } - class Update { + private class Update { - final HttpServerRequest req; - boolean failed; - int queryCount; - final World[] worlds; + private final HttpServerRequest request; + private final World[] worldsToUpdate; + private boolean failed; + private int selectWorldCompletedCount; - public Update(HttpServerRequest req) { - final int queries = getQueries(req); - this.req = req; - this.worlds = new World[queries]; + public Update(HttpServerRequest request) { + this.request = request; + this.worldsToUpdate = new World[getQueries(request)]; } - private void handle() { - - client1.group(c -> { - PreparedQuery> preparedQuery = c.preparedQuery(SELECT_WORLD); - for (int i = 0; i < worlds.length; i++) { - int id = randomWorld(); - int index = i; - preparedQuery.execute(Tuple.of(id), ar2 -> { + public void handle() { + client.group(c -> { + final PreparedQuery> preparedQuery = c.preparedQuery(App.SELECT_WORLD); + for (int i = 0; i < worldsToUpdate.length; i++) { + final Integer id = boxedRandomWorldNumber(); + final int index = i; + preparedQuery.execute(Tuple.of(id), res -> { if (!failed) { - if (ar2.failed()) { + if (res.failed()) { failed = true; - sendError(req, ar2.cause()); + sendError(request, res.cause()); return; } - worlds[index] = new World(ar2.result().iterator().next().getInteger(0), randomWorld()); - if (++queryCount == worlds.length) { - handleUpdates(); + worldsToUpdate[index] = new World(res.result().iterator().next().getInteger(0), boxedRandomWorldNumber()); + if (++selectWorldCompletedCount == worldsToUpdate.length) { + randomWorldsQueryCompleted(); } } }); @@ -388,43 +387,32 @@ private void handle() { }); } - void handleUpdates() { - Arrays.sort(worlds); - int len = worlds.length; - if (0 < len && len <= AGGREGATED_UPDATE_WORLD_QUERY.length) { - List arguments = new ArrayList<>(); - for (World world : worlds) { - arguments.add(world.getId()); - arguments.add(world.getRandomNumber()); - } - Tuple tuple = Tuple.tuple(arguments); - PreparedQuery> query = AGGREGATED_UPDATE_WORLD_QUERY[len - 1]; - query.execute(tuple, this::sendResponse); - } else { - List batch = new ArrayList<>(); - for (World world : worlds) { - batch.add(Tuple.of(world.getRandomNumber(), world.getId())); - } - UPDATE_WORLD_QUERY.executeBatch(batch, this::sendResponse); + private void randomWorldsQueryCompleted() { + Arrays.sort(worldsToUpdate); + final List params = new ArrayList<>(worldsToUpdate.length * 2); + for (int i = 0, count = worldsToUpdate.length;i < count;i++) { + var world = worldsToUpdate[i]; + params.add(world.getId()); + params.add(world.getRandomNumber()); } + AGGREGATED_UPDATE_WORLD_QUERY[worldsToUpdate.length - 1].execute(Tuple.wrap(params), updateResult -> { + if (updateResult.failed()) { + sendError(request, updateResult.cause()); + return; + } + sendResponse(); + }); } - private void sendResponse(AsyncResult res) { - if (res.failed()) { - sendError(req, res.cause()); - return; - } - JsonArray json = new JsonArray(); - for (World world : worlds) { - json.add(world); - } - req.response() - .putHeader(HttpHeaders.SERVER, SERVER) - .putHeader(HttpHeaders.DATE, dateString) - .putHeader(HttpHeaders.CONTENT_TYPE, RESPONSE_TYPE_JSON) - .end(json.toBuffer(), NULL_HANDLER); + private void sendResponse() { + var res = request.response(); + MultiMap headers = res.headers(); + headers.add(HttpHeaders.SERVER, App.SERVER); + headers.add(HttpHeaders.DATE, dateString); + headers.add(HttpHeaders.CONTENT_TYPE, RESPONSE_TYPE_JSON); + Buffer buff = WorldJsonSerializer.toJsonBuffer(worldsToUpdate); + res.end(buff, null); } - } private void handleFortunes(HttpServerRequest req) { @@ -439,11 +427,12 @@ private void handleFortunes(HttpServerRequest req) { List fortunes = result.value(); fortunes.add(new Fortune(0, "Additional fortune added at request time.")); Collections.sort(fortunes); - response - .putHeader(HttpHeaders.SERVER, SERVER) - .putHeader(HttpHeaders.DATE, dateString) - .putHeader(HttpHeaders.CONTENT_TYPE, RESPONSE_TYPE_HTML) - .end(FortunesTemplate.template(fortunes).render(factory).buffer(), NULL_HANDLER); + MultiMap headers = response.headers(); + headers.add(HttpHeaders.SERVER, SERVER); + headers.add(HttpHeaders.DATE, dateString); + headers.add(HttpHeaders.CONTENT_TYPE, RESPONSE_TYPE_HTML); + FortunesTemplate template = FortunesTemplate.template(fortunes); + response.end(template.render(factory).buffer(), NULL_HANDLER); } else { sendError(req, ar.cause()); } @@ -462,19 +451,17 @@ private void handleCaching(HttpServerRequest req) { count = Math.max(1, count); count = Math.min(500, count); List worlds = WORLD_CACHE.getCachedWorld(count); - JsonArray json = new JsonArray(worlds); HttpServerResponse response = req.response(); MultiMap headers = response.headers(); headers .add(HEADER_CONTENT_TYPE, RESPONSE_TYPE_JSON) .add(HEADER_SERVER, SERVER) .add(HEADER_DATE, dateString); - response.end(json.toBuffer(), NULL_HANDLER); + response.end(CachedWorld.toJson(worlds), NULL_HANDLER); } public static void main(String[] args) throws Exception { - - int eventLoopPoolSize = Runtime.getRuntime().availableProcessors(); + int eventLoopPoolSize = NUM_PROCESSORS; String sizeProp = System.getProperty("vertx.eventLoopPoolSize"); if (sizeProp != null) { try { @@ -522,6 +509,7 @@ private static void printConfig(Vertx vertx) { logger.error("Could not read Vertx version", e);; } logger.info("Vertx: " + version); + logger.info("Processors: " + NUM_PROCESSORS); logger.info("Event Loop Size: " + ((MultithreadEventExecutorGroup)vertx.nettyEventLoopGroup()).executorCount()); logger.info("Native transport : " + nativeTransport); logger.info("Transport : " + transport); diff --git a/frameworks/Java/vertx/src/main/java/vertx/model/CachedWorld.java b/frameworks/Java/vertx/src/main/java/vertx/model/CachedWorld.java index f27e8805f33..423d5273f62 100644 --- a/frameworks/Java/vertx/src/main/java/vertx/model/CachedWorld.java +++ b/frameworks/Java/vertx/src/main/java/vertx/model/CachedWorld.java @@ -1,13 +1,17 @@ package vertx.model; -import io.vertx.core.json.JsonObject; +import com.julienviet.jsonsergen.JsonSerGen; +import io.vertx.codegen.annotations.DataObject; +import io.vertx.core.buffer.Buffer; -import java.util.Map; +import java.util.List; /** * The model for the "world" database table. */ -public final class CachedWorld extends JsonObject implements Comparable { +@DataObject +@JsonSerGen +public final class CachedWorld implements Comparable { private final int id; private final int randomNumber; @@ -19,7 +23,6 @@ public final class CachedWorld extends JsonObject implements Comparable worlds) { + return CachedWorldJsonSerializer.toJsonBuffer(worlds); + } } \ No newline at end of file diff --git a/frameworks/Java/vertx/src/main/java/vertx/model/Fortune.java b/frameworks/Java/vertx/src/main/java/vertx/model/Fortune.java index d1df6fcfa1a..eb21f93feee 100644 --- a/frameworks/Java/vertx/src/main/java/vertx/model/Fortune.java +++ b/frameworks/Java/vertx/src/main/java/vertx/model/Fortune.java @@ -7,11 +7,14 @@ /** * The model for the "fortune" database table. */ -public final class Fortune extends JsonObject implements Comparable { +public final class Fortune implements Comparable { private static final String ID = "id"; private static final String MESSAGE = "message"; + private final int id; + private final String message; + /** * Constructs a new fortune object with the given parameters. * @@ -19,20 +22,16 @@ public final class Fortune extends JsonObject implements Comparable { * @param message the message of the fortune */ public Fortune(int id, String message) { - put(ID, id); - put(MESSAGE, message); - } - - public Fortune(JsonObject doc) { - super(doc == null ? Collections.emptyMap() : doc.getMap()); + this.id = id; + this.message = message; } public int getId() { - return getInteger(ID); + return id; } public String getMessage() { - return getString(MESSAGE); + return message; } @Override diff --git a/frameworks/Java/vertx/src/main/java/vertx/model/Message.java b/frameworks/Java/vertx/src/main/java/vertx/model/Message.java index 0fe3274afe0..ce240bd5ae9 100644 --- a/frameworks/Java/vertx/src/main/java/vertx/model/Message.java +++ b/frameworks/Java/vertx/src/main/java/vertx/model/Message.java @@ -1,16 +1,29 @@ package vertx.model; -import io.vertx.core.json.JsonObject; +import com.julienviet.jsonsergen.JsonSerGen; +import io.vertx.codegen.annotations.DataObject; +import io.vertx.core.buffer.Buffer; -public class Message extends JsonObject { +@DataObject +@JsonSerGen +public class Message { - private static final String MESSAGE = "message"; + private String message; public Message(String message) { - put(MESSAGE, message); + this.message = message; } public String getMessage() { - return getString(MESSAGE); + return message; + } + + public Message setMessage(String message) { + this.message = message; + return this; + } + + public Buffer toJson() { + return MessageJsonSerializer.toJsonBuffer(this); } } diff --git a/frameworks/Java/vertx/src/main/java/vertx/model/World.java b/frameworks/Java/vertx/src/main/java/vertx/model/World.java index 86f4d29e99b..43f7bfc2a61 100644 --- a/frameworks/Java/vertx/src/main/java/vertx/model/World.java +++ b/frameworks/Java/vertx/src/main/java/vertx/model/World.java @@ -1,13 +1,15 @@ package vertx.model; -import io.vertx.core.json.JsonObject; - -import java.util.Map; +import com.julienviet.jsonsergen.JsonSerGen; +import io.vertx.codegen.annotations.DataObject; +import io.vertx.core.buffer.Buffer; /** * The model for the "world" database table. */ -public final class World extends JsonObject implements Comparable { +@DataObject +@JsonSerGen +public final class World implements Comparable { private final int id; private final int randomNumber; @@ -19,7 +21,6 @@ public final class World extends JsonObject implements Comparable { * @param randomNumber the random number of the world */ public World(int id, int randomNumber) { - super(Map.of("id", id, "randomNumber", randomNumber)); this.id = id; this.randomNumber = randomNumber; } @@ -36,4 +37,12 @@ public int getRandomNumber() { public int compareTo(World o) { return Integer.compare(id, o.id); } + + public Buffer toJson() { + return WorldJsonSerializer.toJsonBuffer(this); + } + + public static Buffer toJson(World[] worlds) { + return WorldJsonSerializer.toJsonBuffer(worlds); + } } \ No newline at end of file diff --git a/frameworks/Java/vertx/src/main/java/vertx/model/package-info.java b/frameworks/Java/vertx/src/main/java/vertx/model/package-info.java new file mode 100644 index 00000000000..d0dfa9d492c --- /dev/null +++ b/frameworks/Java/vertx/src/main/java/vertx/model/package-info.java @@ -0,0 +1,4 @@ +@ModuleGen(name = "benchmark", groupPackage = "vertx.model") +package vertx.model; + +import io.vertx.codegen.annotations.ModuleGen; \ No newline at end of file diff --git a/frameworks/Java/vertx/vertx-postgres.dockerfile b/frameworks/Java/vertx/vertx-postgres.dockerfile index 3072a3ad381..dec7fa545a3 100644 --- a/frameworks/Java/vertx/vertx-postgres.dockerfile +++ b/frameworks/Java/vertx/vertx-postgres.dockerfile @@ -14,6 +14,7 @@ CMD export DBIP=`getent hosts tfb-database | awk '{ print $1 }'` && \ -server \ -XX:+UseNUMA \ -XX:+UseParallelGC \ + -Djava.lang.Integer.IntegerCache.high=10000 \ -Dvertx.disableMetrics=true \ -Dvertx.disableH2c=true \ -Dvertx.disableWebsockets=true \ diff --git a/frameworks/Java/vertx/vertx.dockerfile b/frameworks/Java/vertx/vertx.dockerfile index cfd269e37ae..2fe2a27a2c2 100644 --- a/frameworks/Java/vertx/vertx.dockerfile +++ b/frameworks/Java/vertx/vertx.dockerfile @@ -6,4 +6,4 @@ RUN mvn package -q EXPOSE 8080 -CMD ["java", "-Xms2G", "-Xmx2G", "-server", "-XX:+UseNUMA", "-XX:+UseParallelGC", "-Dvertx.disableMetrics=true", "-Dvertx.disableH2c=true", "-Dvertx.disableWebsockets=true", "-Dvertx.flashPolicyHandler=false", "-Dvertx.threadChecks=false", "-Dvertx.disableContextTimings=true", "-Dvertx.disableTCCL=true", "-Dvertx.disableHttpHeadersValidation=true", "-Dio.netty.buffer.checkBounds=false", "-Dio.netty.buffer.checkAccessible=false", "-jar", "target/vertx.benchmark-0.0.1-SNAPSHOT-fat.jar", "src/main/conf/config.json"] +CMD ["java", "-Xms2G", "-Xmx2G", "-server", "-XX:+UseNUMA", "-XX:+UseParallelGC", "-Djava.lang.Integer.IntegerCache.high=10000", "-Dvertx.disableMetrics=true", "-Dvertx.disableH2c=true", "-Dvertx.disableWebsockets=true", "-Dvertx.flashPolicyHandler=false", "-Dvertx.threadChecks=false", "-Dvertx.disableContextTimings=true", "-Dvertx.disableTCCL=true", "-Dvertx.disableHttpHeadersValidation=true", "-Dio.netty.buffer.checkBounds=false", "-Dio.netty.buffer.checkAccessible=false", "-jar", "target/vertx.benchmark-0.0.1-SNAPSHOT-fat.jar", "src/main/conf/config.json"] From 57f2f117488029a625feea0605f7da76bfb2a0b9 Mon Sep 17 00:00:00 2001 From: Anton Kirilov Date: Fri, 26 Jul 2024 17:50:09 +0100 Subject: [PATCH 044/204] H2O: Use 2 database connections per thread again (#9176) --- frameworks/C/h2o/h2o.dockerfile | 2 +- frameworks/C/h2o/src/handlers/world.c | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/frameworks/C/h2o/h2o.dockerfile b/frameworks/C/h2o/h2o.dockerfile index cfabc77bb3b..bca0d12b19e 100644 --- a/frameworks/C/h2o/h2o.dockerfile +++ b/frameworks/C/h2o/h2o.dockerfile @@ -109,4 +109,4 @@ CMD ["taskset", \ "dbname=hello_world host=tfb-database password=benchmarkdbpass sslmode=disable user=benchmarkdbuser", \ "-f", \ "/opt/h2o_app/share/h2o_app/template", \ - "-m1"] + "-m2"] diff --git a/frameworks/C/h2o/src/handlers/world.c b/frameworks/C/h2o/src/handlers/world.c index a87ee4c4282..82d29ce08b8 100644 --- a/frameworks/C/h2o/src/handlers/world.c +++ b/frameworks/C/h2o/src/handlers/world.c @@ -237,9 +237,9 @@ static int do_multiple_queries(bool do_update, bool use_cache, h2o_req_t *req) const size_t num_query = get_query_number(req); - // MAX_QUERIES is a relatively small number, so assume no overflow in the following - // arithmetic operations. - assert(num_query && num_query <= MAX_QUERIES); + // MAX_QUERIES is a relatively small number, say less than or equal to UINT16_MAX, so assume no + // overflow in the following arithmetic operations. + assert(num_query && num_query <= MAX_QUERIES && num_query <= UINT16_MAX); size_t base_size = offsetof(multiple_query_ctx_t, res) + num_query * sizeof(query_result_t); @@ -373,7 +373,7 @@ static void do_updates(multiple_query_ctx_t *query_ctx) for (size_t i = 0; i < query_ctx->num_result; i++) { query_ctx->res[i].id = htonl(query_ctx->res[i].id); query_ctx->res[i].random_number = - htonl(1 + get_random_number(MAX_ID, &query_ctx->ctx->random_seed)); + htonl(1 + get_random_number(MAX_ID, &query_ctx->ctx->random_seed)); paramFormats[2 * i] = 1; paramFormats[2 * i + 1] = 1; paramLengths[2 * i] = sizeof(query_ctx->res[i].id); From f2a87b60800fac06a293cc5e1270a78e8cba05d0 Mon Sep 17 00:00:00 2001 From: Joan Miquel Date: Mon, 29 Jul 2024 23:14:27 +0200 Subject: [PATCH 045/204] [php] Fix Swoole and faster docker builds (#9169) * Fix Symfony Swoole * Fix Laravel Swoole * Fix Simps Swoole * Fix Laravel Laravels Swoole variant * Fix Lumen Swoole variants * Fix MixPHP Swoole * Fix Ubiquity Swoole variants --- .../PHP/laravel/laravel-laravel-s.dockerfile | 18 ++++-------- .../PHP/laravel/laravel-swoole.dockerfile | 20 ++++--------- .../PHP/lumen/lumen-laravel-s.dockerfile | 15 +++------- frameworks/PHP/lumen/lumen-swoole.dockerfile | 29 +++++-------------- .../PHP/mixphp/mixphp-swoole-mysql.dockerfile | 18 ++++-------- frameworks/PHP/simps/simps-micro.dockerfile | 17 ++++------- frameworks/PHP/simps/simps.dockerfile | 17 ++++------- frameworks/PHP/symfony/public/swoole.php | 2 +- .../PHP/symfony/symfony-swoole.dockerfile | 13 +++------ .../ubiquity/ubiquity-swoole-mysql.dockerfile | 24 ++++----------- .../PHP/ubiquity/ubiquity-swoole.dockerfile | 22 ++++---------- 11 files changed, 53 insertions(+), 142 deletions(-) diff --git a/frameworks/PHP/laravel/laravel-laravel-s.dockerfile b/frameworks/PHP/laravel/laravel-laravel-s.dockerfile index 4cce4090f3d..a0e946e5097 100644 --- a/frameworks/PHP/laravel/laravel-laravel-s.dockerfile +++ b/frameworks/PHP/laravel/laravel-laravel-s.dockerfile @@ -1,25 +1,17 @@ -FROM php:8.3-cli +FROM phpswoole/swoole:5.1.3-php8.3 -RUN pecl install swoole > /dev/null && \ - docker-php-ext-enable swoole -RUN docker-php-ext-install pdo_mysql pcntl opcache > /dev/null +RUN docker-php-ext-install pcntl opcache curl > /dev/null RUN echo "opcache.enable_cli=1" >> /usr/local/etc/php/conf.d/docker-php-ext-opcache.ini RUN echo "opcache.jit=1205" >> /usr/local/etc/php/conf.d/docker-php-ext-opcache.ini RUN echo "opcache.jit_buffer_size=128M" >> /usr/local/etc/php/conf.d/docker-php-ext-opcache.ini -ADD ./ /laravel WORKDIR /laravel +COPY --link . . RUN mkdir -p /laravel/bootstrap/cache /laravel/storage/logs /laravel/storage/framework/sessions /laravel/storage/framework/views /laravel/storage/framework/cache -RUN chmod -R 777 /laravel -RUN apt-get update > /dev/null && \ - apt-get install -yqq git unzip > /dev/null -RUN php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');" && php composer-setup.php && php -r "unlink('composer-setup.php');" -RUN mv composer.phar /usr/local/bin/composer - -COPY deploy/laravel-s/composer.json ./ +COPY --link deploy/laravel-s/composer.json . RUN echo "LARAVELS_LISTEN_IP=0.0.0.0" >> .env RUN echo "LARAVELS_LISTEN_PORT=8080" >> .env @@ -30,4 +22,4 @@ RUN php artisan laravels publish EXPOSE 8080 -CMD php bin/laravels start +ENTRYPOINT [ "php", "bin/laravels", "start" ] diff --git a/frameworks/PHP/laravel/laravel-swoole.dockerfile b/frameworks/PHP/laravel/laravel-swoole.dockerfile index 77cfef19fe0..3882a7ac4c8 100644 --- a/frameworks/PHP/laravel/laravel-swoole.dockerfile +++ b/frameworks/PHP/laravel/laravel-swoole.dockerfile @@ -1,33 +1,23 @@ -FROM php:8.3-cli +FROM phpswoole/swoole:5.1.3-php8.3 -RUN pecl install swoole > /dev/null && \ - docker-php-ext-enable swoole -RUN docker-php-ext-install pdo_mysql pcntl opcache > /dev/null +RUN docker-php-ext-install pcntl opcache curl > /dev/null RUN echo "opcache.enable_cli=1" >> /usr/local/etc/php/conf.d/docker-php-ext-opcache.ini RUN echo "opcache.jit=1205" >> /usr/local/etc/php/conf.d/docker-php-ext-opcache.ini RUN echo "opcache.jit_buffer_size=128M" >> /usr/local/etc/php/conf.d/docker-php-ext-opcache.ini -ADD ./ /laravel WORKDIR /laravel +COPY --link . . RUN mkdir -p /laravel/bootstrap/cache /laravel/storage/framework/sessions /laravel/storage/framework/views /laravel/storage/framework/cache -RUN chmod -R 777 /laravel -RUN apt-get update -yqq > /dev/null && \ - apt-get install -yqq git unzip > /dev/null - -RUN php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');" && php composer-setup.php && php -r "unlink('composer-setup.php');" -RUN mv composer.phar /usr/local/bin/composer - -COPY deploy/swoole/composer.json ./ +COPY --link deploy/swoole/composer.json . RUN echo "APP_SWOOLE=true" >> .env RUN composer install -a --no-dev --quiet RUN php artisan optimize - EXPOSE 8080 -CMD php artisan swoole:http start +ENTRYPOINT [ "php", "artisan", "swoole:http", "start" ] diff --git a/frameworks/PHP/lumen/lumen-laravel-s.dockerfile b/frameworks/PHP/lumen/lumen-laravel-s.dockerfile index a8a0aebd68a..a2b4be68310 100644 --- a/frameworks/PHP/lumen/lumen-laravel-s.dockerfile +++ b/frameworks/PHP/lumen/lumen-laravel-s.dockerfile @@ -1,24 +1,17 @@ -FROM php:8.3-cli +FROM phpswoole/swoole:5.1.3-php8.3 -RUN pecl install swoole > /dev/null && \ - docker-php-ext-enable swoole -RUN docker-php-ext-install pdo_mysql pcntl opcache > /dev/null +RUN docker-php-ext-install pcntl opcache curl > /dev/null RUN echo "opcache.enable_cli=1" >> /usr/local/etc/php/conf.d/docker-php-ext-opcache.ini #RUN echo "opcache.jit=1205" >> /usr/local/etc/php/conf.d/docker-php-ext-opcache.ini #RUN echo "opcache.jit_buffer_size=128M" >> /usr/local/etc/php/conf.d/docker-php-ext-opcache.ini -ADD ./ /lumen WORKDIR /lumen +ADD --link . . RUN mkdir -p /lumen/bootstrap/cache /lumen/storage/logs /lumen/storage/framework/sessions /lumen/storage/framework/views /lumen/storage/framework/cache RUN chmod -R 777 /lumen -RUN apt-get update > /dev/null && \ - apt-get install -yqq git unzip > /dev/null -RUN php -r "copy('https://install.phpcomposer.com/installer', 'composer-setup.php');" && php composer-setup.php && php -r "unlink('composer-setup.php');" -RUN mv composer.phar /usr/local/bin/composer - COPY deploy/laravel-s/composer.json ./ RUN echo "LARAVELS_LISTEN_IP=0.0.0.0" >> .env @@ -29,4 +22,4 @@ RUN php artisan laravels publish EXPOSE 8080 -CMD php bin/laravels start +ENTRYPOINT [ "php", "bin/laravels", "start" ] diff --git a/frameworks/PHP/lumen/lumen-swoole.dockerfile b/frameworks/PHP/lumen/lumen-swoole.dockerfile index 3e4c866c031..de3d4294973 100644 --- a/frameworks/PHP/lumen/lumen-swoole.dockerfile +++ b/frameworks/PHP/lumen/lumen-swoole.dockerfile @@ -1,31 +1,16 @@ -FROM php:8.3-cli +FROM phpswoole/swoole:5.1.3-php8.3 -RUN pecl install swoole > /dev/null && \ - docker-php-ext-enable swoole +RUN docker-php-ext-install pcntl opcache curl > /dev/null -RUN docker-php-ext-install pdo_mysql > /dev/null - -ADD ./ /lumen WORKDIR /lumen -COPY deploy/swoole/php.ini /usr/local/etc/php/ - -RUN mkdir -p /lumen/storage/framework/sessions -RUN mkdir -p /lumen/storage/framework/views -RUN mkdir -p /lumen/storage/framework/cache - -RUN chmod -R 777 /lumen +ADD --link . . -# Install composer using the installation method documented at https://getcomposer.org/doc/faqs/how-to-install-composer-programmatically.md -# This method was chosen because composer is not part of the apt repositories that are in the default PHP 7.2 docker image -# Adding alternate apt php repos can potentially cause problems with extension compatibility between the php build from the docker image and the alternate php build -# An additional benefit of this method is that the correct version of composer will be used for the environment and version of the php system in the docker image -RUN deploy/swoole/install-composer.sh +COPY --link deploy/swoole/php.ini /usr/local/etc/php/ -RUN apt-get update -yqq > /dev/null && \ - apt-get install -yqq git unzip > /dev/null +RUN mkdir -p /lumen/storage/framework/sessions /lumen/storage/framework/views /lumen/storage/framework/cache COPY deploy/swoole/composer* ./ -RUN php composer.phar install --optimize-autoloader --classmap-authoritative --no-dev --quiet +RUN composer install --optimize-autoloader --classmap-authoritative --no-dev --quiet RUN echo "APP_SWOOLE=true" >> .env @@ -33,4 +18,4 @@ RUN chmod -R 777 /lumen EXPOSE 8080 -CMD php artisan swoole:http start +ENTRYPOINT [ "php", "artisan", "swoole:http", "start" ] diff --git a/frameworks/PHP/mixphp/mixphp-swoole-mysql.dockerfile b/frameworks/PHP/mixphp/mixphp-swoole-mysql.dockerfile index 2001b9fde1d..846a3b88a87 100644 --- a/frameworks/PHP/mixphp/mixphp-swoole-mysql.dockerfile +++ b/frameworks/PHP/mixphp/mixphp-swoole-mysql.dockerfile @@ -1,13 +1,10 @@ -FROM php:8.3-cli +FROM phpswoole/swoole:5.1.3-php8.3 -RUN pecl install swoole > /dev/null && docker-php-ext-enable swoole +RUN docker-php-ext-install pcntl opcache bcmath > /dev/null -RUN docker-php-ext-install opcache pdo_mysql bcmath > /dev/null - -RUN apt -yqq update && apt -yqq install git unzip > /dev/null - -COPY . /mixphp -COPY php.ini /usr/local/etc/php/ +WORKDIR /mixphp +COPY --link . . +COPY --link php.ini /usr/local/etc/php/ RUN echo "opcache.enable=1" >> /usr/local/etc/php/php.ini RUN echo "opcache.enable_cli=1" >> /usr/local/etc/php/php.ini RUN echo "pcre.jit=1" >> /usr/local/etc/php/php.ini @@ -16,9 +13,6 @@ RUN echo "opcache.jit_buffer_size=256M" >> /usr/local/etc/php/php.ini RUN php -v && php -i | grep opcache -WORKDIR /mixphp - -COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer RUN composer install --no-dev --classmap-authoritative --quiet > /dev/null RUN composer dumpautoload -o @@ -27,4 +21,4 @@ RUN chmod -R 777 /mixphp/runtime/logs EXPOSE 9501 -CMD php /mixphp/bin/swoole.php start +ENTRYPOINT [ "php", "/mixphp/bin/swoole.php", "start" ] diff --git a/frameworks/PHP/simps/simps-micro.dockerfile b/frameworks/PHP/simps/simps-micro.dockerfile index baa74e103e1..4e5b9ffd075 100644 --- a/frameworks/PHP/simps/simps-micro.dockerfile +++ b/frameworks/PHP/simps/simps-micro.dockerfile @@ -1,22 +1,15 @@ -FROM php:8.3-cli +FROM phpswoole/swoole:5.1.3-php8.3 -RUN pecl install swoole > /dev/null && \ - docker-php-ext-enable swoole - -RUN docker-php-ext-install opcache pdo_mysql > /dev/null - -RUN apt -yqq update > /dev/null && \ - apt -yqq install git unzip > /dev/null +RUN docker-php-ext-install pcntl opcache curl > /dev/null WORKDIR /simps -COPY . /simps -COPY php.ini /usr/local/etc/php/ +COPY --link . . +COPY --link php.ini /usr/local/etc/php/ -RUN curl -sSL https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer RUN composer install --no-dev --classmap-authoritative --quiet > /dev/null RUN composer dumpautoload -o EXPOSE 8080 -CMD php sbin/simps.php http:start +ENTRYPOINT [ "php", "sbin/simps.php", "http:start" ] diff --git a/frameworks/PHP/simps/simps.dockerfile b/frameworks/PHP/simps/simps.dockerfile index baa74e103e1..4e5b9ffd075 100644 --- a/frameworks/PHP/simps/simps.dockerfile +++ b/frameworks/PHP/simps/simps.dockerfile @@ -1,22 +1,15 @@ -FROM php:8.3-cli +FROM phpswoole/swoole:5.1.3-php8.3 -RUN pecl install swoole > /dev/null && \ - docker-php-ext-enable swoole - -RUN docker-php-ext-install opcache pdo_mysql > /dev/null - -RUN apt -yqq update > /dev/null && \ - apt -yqq install git unzip > /dev/null +RUN docker-php-ext-install pcntl opcache curl > /dev/null WORKDIR /simps -COPY . /simps -COPY php.ini /usr/local/etc/php/ +COPY --link . . +COPY --link php.ini /usr/local/etc/php/ -RUN curl -sSL https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer RUN composer install --no-dev --classmap-authoritative --quiet > /dev/null RUN composer dumpautoload -o EXPOSE 8080 -CMD php sbin/simps.php http:start +ENTRYPOINT [ "php", "sbin/simps.php", "http:start" ] diff --git a/frameworks/PHP/symfony/public/swoole.php b/frameworks/PHP/symfony/public/swoole.php index 2c0695003f4..a1825fc344e 100644 --- a/frameworks/PHP/symfony/public/swoole.php +++ b/frameworks/PHP/symfony/public/swoole.php @@ -15,6 +15,6 @@ require_once dirname(__DIR__).'/vendor/autoload_runtime.php'; -return function (array $context) { +return function (array $context): Kernel { return new Kernel($context['APP_ENV'], (bool) $context['APP_DEBUG']); }; diff --git a/frameworks/PHP/symfony/symfony-swoole.dockerfile b/frameworks/PHP/symfony/symfony-swoole.dockerfile index 37403a24c97..e8fda091bb3 100644 --- a/frameworks/PHP/symfony/symfony-swoole.dockerfile +++ b/frameworks/PHP/symfony/symfony-swoole.dockerfile @@ -1,16 +1,11 @@ -FROM php:8.3-cli - -RUN pecl install swoole > /dev/null && \ - docker-php-ext-enable swoole - -RUN pecl install apcu > /dev/null && \ - docker-php-ext-enable apcu +FROM phpswoole/swoole:5.1.3-php8.3 RUN apt-get update -yqq && \ - apt-get install -yqq libpq-dev libicu-dev git unzip > /dev/null && \ + apt-get install -yqq libpq-dev libicu-dev > /dev/null && \ docker-php-ext-install pdo_pgsql opcache intl > /dev/null -COPY --from=composer/composer:latest-bin --link /composer /usr/local/bin/composer +RUN pecl install apcu > /dev/null && \ + docker-php-ext-enable apcu COPY --link deploy/swoole/php.ini /usr/local/etc/php/ WORKDIR /symfony diff --git a/frameworks/PHP/ubiquity/ubiquity-swoole-mysql.dockerfile b/frameworks/PHP/ubiquity/ubiquity-swoole-mysql.dockerfile index d4195a1d945..7a99706faaf 100644 --- a/frameworks/PHP/ubiquity/ubiquity-swoole-mysql.dockerfile +++ b/frameworks/PHP/ubiquity/ubiquity-swoole-mysql.dockerfile @@ -1,29 +1,17 @@ -FROM php:8.3-cli +FROM phpswoole/swoole:5.1.3-php8.3 -RUN apt-get update > /dev/null - -RUN pecl install swoole > /dev/null && \ - docker-php-ext-enable swoole - -RUN docker-php-ext-install pdo_mysql opcache pcntl > /dev/null +RUN docker-php-ext-install pcntl opcache > /dev/null COPY deploy/conf/php-async.ini /usr/local/etc/php/php.ini -ADD ./ /ubiquity WORKDIR /ubiquity +ADD --link . . RUN chmod -R 777 /ubiquity -RUN ["chmod", "+x", "deploy/run/install-composer.sh"] - -RUN deploy/run/install-composer.sh - -RUN apt-get update -yqq > /dev/null && \ - apt-get install -yqq git unzip > /dev/null - -RUN php composer.phar require phpmv/ubiquity-devtools:dev-master phpmv/ubiquity-swoole:dev-master --quiet +RUN composer require phpmv/ubiquity-devtools:dev-master phpmv/ubiquity-swoole:dev-master --quiet -RUN php composer.phar install --optimize-autoloader --classmap-authoritative --no-dev --quiet +RUN composer install --optimize-autoloader --classmap-authoritative --no-dev --quiet RUN chmod 777 -R /ubiquity/.ubiquity/* @@ -36,4 +24,4 @@ COPY deploy/conf/swoole/mysql/swooleServices.php app/config/swooleServices.php EXPOSE 8080 -CMD /ubiquity/vendor/bin/Ubiquity serve -t=swoole -p=8080 -h=0.0.0.0 +ENTRYPOINT [ "/ubiquity/vendor/bin/Ubiquity", "serve", "-t=swoole", "-p=8080", "-h=0.0.0.0" ] diff --git a/frameworks/PHP/ubiquity/ubiquity-swoole.dockerfile b/frameworks/PHP/ubiquity/ubiquity-swoole.dockerfile index ff57c3c54e1..d4807c4a8ad 100644 --- a/frameworks/PHP/ubiquity/ubiquity-swoole.dockerfile +++ b/frameworks/PHP/ubiquity/ubiquity-swoole.dockerfile @@ -1,9 +1,4 @@ -FROM php:8.3-cli - -RUN apt-get update > /dev/null - -RUN pecl install swoole > /dev/null && \ - docker-php-ext-enable swoole +FROM phpswoole/swoole:5.1.3-php8.3 RUN apt-get install -y libpq-dev \ && docker-php-ext-configure pgsql -with-pgsql=/usr/local/pgsql \ @@ -11,21 +6,14 @@ RUN apt-get install -y libpq-dev \ COPY deploy/conf/php-async.ini /usr/local/etc/php/php.ini -ADD ./ /ubiquity WORKDIR /ubiquity +ADD --link . . RUN chmod -R 777 /ubiquity -RUN ["chmod", "+x", "deploy/run/install-composer.sh"] - -RUN deploy/run/install-composer.sh - -RUN apt-get update -yqq > /dev/null && \ - apt-get install -yqq git unzip > /dev/null - -RUN php composer.phar require phpmv/ubiquity-devtools:dev-master phpmv/ubiquity-swoole:dev-master --quiet +RUN composer require phpmv/ubiquity-devtools:dev-master phpmv/ubiquity-swoole:dev-master --quiet -RUN php composer.phar install --optimize-autoloader --classmap-authoritative --no-dev --quiet +RUN composer install --optimize-autoloader --classmap-authoritative --no-dev --quiet RUN chmod 777 -R /ubiquity/.ubiquity/* @@ -38,4 +26,4 @@ COPY deploy/conf/swoole/pgsql/swooleServices.php app/config/swooleServices.php EXPOSE 8080 -CMD /ubiquity/vendor/bin/Ubiquity serve -t=swoole -p=8080 -h=0.0.0.0 +ENTRYPOINT [ "/ubiquity/vendor/bin/Ubiquity", "serve", "-t=swoole", "-p=8080", "-h=0.0.0.0" ] From 723dd6eeb2dc6a8c9e3d8f2f24f0b5c17acb39e6 Mon Sep 17 00:00:00 2001 From: Joan Miquel Date: Wed, 31 Jul 2024 20:19:05 +0200 Subject: [PATCH 046/204] Update to MySQL 9.0 (#9183) --- toolset/databases/mysql/create.sql | 6 +++--- toolset/databases/mysql/my.cnf | 2 +- toolset/databases/mysql/mysql.dockerfile | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/toolset/databases/mysql/create.sql b/toolset/databases/mysql/create.sql index 94cb995deb3..d97fb37f490 100644 --- a/toolset/databases/mysql/create.sql +++ b/toolset/databases/mysql/create.sql @@ -2,14 +2,14 @@ # http://stackoverflow.com/questions/37719818/the-server-time-zone-value-aest-is-unrecognized-or-represents-more-than-one-ti SET GLOBAL time_zone = '+00:00'; -CREATE USER IF NOT EXISTS 'benchmarkdbuser'@'%' IDENTIFIED WITH mysql_native_password BY 'benchmarkdbpass'; -CREATE USER IF NOT EXISTS 'benchmarkdbuser'@'localhost' IDENTIFIED WITH mysql_native_password BY 'benchmarkdbpass'; +CREATE USER IF NOT EXISTS 'benchmarkdbuser'@'%' IDENTIFIED WITH caching_sha2_password BY 'benchmarkdbpass'; +CREATE USER IF NOT EXISTS 'benchmarkdbuser'@'localhost' IDENTIFIED WITH caching_sha2_password BY 'benchmarkdbpass'; -- GitHub Actions/CI run the database server on the same system as the benchmarks. -- Because we setup MySQL with the skip-name-resolve option, the IP address 127.0.0.1 might not be resolved to localhost -- anymore. This does not seem to matter, as long as Unix sockets are being used (e.g. when setting up the docker image), -- because the host is set to be localhost implicitly, but it matters for local TCP connections. -CREATE USER IF NOT EXISTS 'benchmarkdbuser'@'127.0.0.1' IDENTIFIED WITH mysql_native_password BY 'benchmarkdbpass'; +CREATE USER IF NOT EXISTS 'benchmarkdbuser'@'127.0.0.1' IDENTIFIED WITH caching_sha2_password BY 'benchmarkdbpass'; # modified from SO answer http://stackoverflow.com/questions/5125096/for-loop-in-mysql CREATE DATABASE IF NOT EXISTS hello_world; diff --git a/toolset/databases/mysql/my.cnf b/toolset/databases/mysql/my.cnf index 40ffa8dd9eb..e1a401ae2d9 100644 --- a/toolset/databases/mysql/my.cnf +++ b/toolset/databases/mysql/my.cnf @@ -16,7 +16,7 @@ default-character-set=utf8 # * Basic Settings # default-storage-engine = innodb -mysql_native_password = ON +#mysql_native_password = ON # disabled in v9 #default_authentication_plugin = mysql_native_password user = mysql diff --git a/toolset/databases/mysql/mysql.dockerfile b/toolset/databases/mysql/mysql.dockerfile index 1aae5eb7d38..b5c5b6a67bb 100644 --- a/toolset/databases/mysql/mysql.dockerfile +++ b/toolset/databases/mysql/mysql.dockerfile @@ -1,4 +1,4 @@ -FROM mysql:8.4 +FROM mysql:9.0 ENV MYSQL_ROOT_PASSWORD=root ENV MYSQL_USER=benchmarkdbuser From 31599d26230c61f5d15714fea01447d7926a8529 Mon Sep 17 00:00:00 2001 From: Joan Miquel Date: Wed, 31 Jul 2024 20:19:18 +0200 Subject: [PATCH 047/204] Fix Nodejs mysql-raw.js (#9184) --- frameworks/JavaScript/nodejs/handlers/mysql-raw.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frameworks/JavaScript/nodejs/handlers/mysql-raw.js b/frameworks/JavaScript/nodejs/handlers/mysql-raw.js index 5fa1ea3c625..6063b4020e4 100644 --- a/frameworks/JavaScript/nodejs/handlers/mysql-raw.js +++ b/frameworks/JavaScript/nodejs/handlers/mysql-raw.js @@ -1,6 +1,6 @@ const h = require('../helper'); const async = require('async'); -const mysql = require('mysql'); +const mysql = require('mysql2'); const connection = mysql.createConnection({ host: 'tfb-database', user: 'benchmarkdbuser', From 536f6cfea5d91808e81276592ba602c477f41f97 Mon Sep 17 00:00:00 2001 From: Nikolay Kim Date: Wed, 31 Jul 2024 20:19:28 +0200 Subject: [PATCH 048/204] ntex: Upgrade to ntex-2.0 (#9185) --- frameworks/Rust/ntex/Cargo.toml | 11 +++++----- frameworks/Rust/ntex/src/db.rs | 31 +++++++++++++++------------- frameworks/Rust/ntex/src/main_plt.rs | 2 +- frameworks/Rust/ntex/src/utils.rs | 5 ++--- 4 files changed, 26 insertions(+), 23 deletions(-) diff --git a/frameworks/Rust/ntex/Cargo.toml b/frameworks/Rust/ntex/Cargo.toml index b1aff0f6435..6699c6c0f1d 100755 --- a/frameworks/Rust/ntex/Cargo.toml +++ b/frameworks/Rust/ntex/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ntex" -version = "1.0.0" +version = "2.0.0" edition = "2018" [[bin]] @@ -37,22 +37,23 @@ tokio = ["ntex/tokio"] async-std = ["ntex/async-std"] [dependencies] -ntex = "1.0.0" +ntex = "=2.0.3" ntex-bytes = { version = "0.1.21", features=["simd"] } mimalloc = { version = "0.1.25", default-features = false } snmalloc-rs = { version = "0.3.3", features = ["native-cpu"] } yarte = { version = "0.15", features = ["bytes-buf", "json"] } buf-min = { version = "0.7", features = ["ntex-bytes"] } -env_logger = "0.10" +env_logger = "0.11" nanorand = { version = "0.7", default-features = false, features = ["std", "wyrand", "tls"] } atoi = "2.0" num_cpus = "1.16" -smallvec = "1.11" +smallvec = "1.13" +futures = "0.3" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" log = { version = "0.4", features = ["release_max_level_off"] } tok_io = {version = "1", package = "tokio" } -tokio-postgres = { git="https://github.com/fafhrd91/postgres.git", branch="ntex-1.0" } +tokio-postgres = { git="https://github.com/fafhrd91/postgres.git", branch="ntex-2" } [profile.release] opt-level = 3 diff --git a/frameworks/Rust/ntex/src/db.rs b/frameworks/Rust/ntex/src/db.rs index 578465a90e2..5bceed5b73e 100644 --- a/frameworks/Rust/ntex/src/db.rs +++ b/frameworks/Rust/ntex/src/db.rs @@ -1,10 +1,11 @@ use std::{cell::RefCell, fmt::Write as FmtWrite}; +use futures::stream::{futures_unordered::FuturesUnordered, StreamExt}; use nanorand::{Rng, WyRand}; use ntex::util::{BufMut, Bytes, BytesMut}; use smallvec::SmallVec; use tokio_postgres::types::ToSql; -use tokio_postgres::{connect, Client, Statement}; +use tokio_postgres::{connect, Client, Row, Statement}; use yarte::{ywrite_html, Serialize}; use super::utils; @@ -82,7 +83,7 @@ impl PgConnection { let row = self.cl.query_one(&self.world, &[&random_id]).await.unwrap(); let mut body = self.buf.borrow_mut(); - utils::reserve(&mut body); + utils::reserve(&mut body, 256); World { id: row.get(0), randomnumber: row.get(1), @@ -91,17 +92,20 @@ impl PgConnection { body.split().freeze() } + async fn get_one_world(&self, id: i32) -> Row { + self.cl.query_one(&self.world, &[&id]).await.unwrap() + } + pub async fn get_worlds(&self, num: usize) -> Bytes { let mut rng = self.rng.clone(); - let mut queries = SmallVec::<[_; 32]>::new(); + let mut queries = FuturesUnordered::new(); (0..num).for_each(|_| { let w_id = (rng.generate::() % 10_000 + 1) as i32; - queries.push(self.cl.query_one(&self.world, &[&w_id])); + queries.push(self.get_one_world(w_id)) }); let mut worlds = SmallVec::<[_; 32]>::new(); - for fut in queries { - let row = fut.await.unwrap(); + while let Some(row) = queries.next().await { worlds.push(World { id: row.get(0), randomnumber: row.get(1), @@ -109,7 +113,7 @@ impl PgConnection { } let mut body = self.buf.borrow_mut(); - utils::reserve(&mut body); + utils::reserve(&mut body, 8 * 1024); body.put_u8(b'['); worlds.iter().for_each(|w| { w.to_bytes_mut(&mut *body); @@ -121,16 +125,15 @@ impl PgConnection { } pub async fn update(&self, num: usize) -> Bytes { - let mut rng = nanorand::tls_rng(); - let mut queries = SmallVec::<[_; 32]>::new(); + let mut rng = self.rng.clone(); + let mut queries = FuturesUnordered::new(); (0..num).for_each(|_| { let w_id = (rng.generate::() % 10_000 + 1) as i32; - queries.push(self.cl.query_one(&self.world, &[&w_id])); + queries.push(self.get_one_world(w_id)) }); let mut worlds = SmallVec::<[_; 32]>::new(); - for fut in queries.into_iter() { - let row = fut.await.unwrap(); + while let Some(row) = queries.next().await { worlds.push(World { id: row.get(0), randomnumber: (rng.generate::() % 10_000 + 1) as i32, @@ -148,7 +151,7 @@ impl PgConnection { let _ = self.cl.query(&self.updates[num - 1], ¶ms).await; let mut body = self.buf.borrow_mut(); - utils::reserve(&mut body); + utils::reserve(&mut body, 8 * 1024); body.put_u8(b'['); worlds.iter().for_each(|w| { w.to_bytes_mut(&mut *body); @@ -174,7 +177,7 @@ impl PgConnection { fortunes.sort_by(|it, next| it.message.cmp(next.message)); let mut body = std::mem::replace(&mut *self.buf.borrow_mut(), BytesMut::new()); - utils::reserve(&mut body); + utils::reserve(&mut body, 8 * 1024); ywrite_html!(body, "{{> fortune }}"); let result = body.split().freeze(); let _ = std::mem::replace(&mut *self.buf.borrow_mut(), body); diff --git a/frameworks/Rust/ntex/src/main_plt.rs b/frameworks/Rust/ntex/src/main_plt.rs index 4e9279d4ebf..cda9b69fa15 100644 --- a/frameworks/Rust/ntex/src/main_plt.rs +++ b/frameworks/Rust/ntex/src/main_plt.rs @@ -35,7 +35,7 @@ impl Future for App { Ok((req, _)) => { let _ = this.io.with_write_buf(|buf| { buf.with_bytes_mut(|buf| { - utils::reserve(buf); + utils::reserve(buf, 2 * 1024); match req.path() { "/json" => { buf.extend_from_slice(JSON); diff --git a/frameworks/Rust/ntex/src/utils.rs b/frameworks/Rust/ntex/src/utils.rs index 5792506dd71..719d5962dd4 100644 --- a/frameworks/Rust/ntex/src/utils.rs +++ b/frameworks/Rust/ntex/src/utils.rs @@ -11,7 +11,6 @@ pub const HDR_HTML_CONTENT_TYPE: HeaderValue = HeaderValue::from_static("text/html; charset=utf-8"); pub const BODY_PLAIN_TEXT: Bytes = Bytes::from_static(b"Hello, World!"); -const LW: usize = 1024; const HW: usize = 128 * 1024; pub const SIZE: usize = 27; @@ -25,9 +24,9 @@ pub fn get_query_param(query: Option<&str>) -> usize { cmp::min(500, cmp::max(1, q) as usize) } -pub fn reserve(buf: &mut BytesMut) { +pub fn reserve(buf: &mut BytesMut, lw: usize) { let remaining = buf.remaining_mut(); - if remaining < LW { + if remaining < lw { buf.reserve(HW); } } From 2777f0a10cc787a64d7faedc51191d61426c48e0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 31 Jul 2024 18:20:13 +0000 Subject: [PATCH 049/204] Bump mysql2 from 3.9.7 to 3.9.8 in /frameworks/JavaScript/hapi Bumps [mysql2](https://github.com/sidorares/node-mysql2) from 3.9.7 to 3.9.8. - [Release notes](https://github.com/sidorares/node-mysql2/releases) - [Changelog](https://github.com/sidorares/node-mysql2/blob/master/Changelog.md) - [Commits](https://github.com/sidorares/node-mysql2/compare/v3.9.7...v3.9.8) --- updated-dependencies: - dependency-name: mysql2 dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- frameworks/JavaScript/hapi/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frameworks/JavaScript/hapi/package.json b/frameworks/JavaScript/hapi/package.json index 5d6070a266a..6a6c23a897b 100644 --- a/frameworks/JavaScript/hapi/package.json +++ b/frameworks/JavaScript/hapi/package.json @@ -10,7 +10,7 @@ "handlebars": "4.3.0", "mongoose": "5.13.20", "mysql": "2.16.0", - "mysql2": "3.9.7", + "mysql2": "3.9.8", "pg": "8.5.1", "pg-hstore": "2.3.2", "sequelize": "6.29.0" From 7b0f9539052ca4d7becb9fcf56d2bb06c62c251f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 31 Jul 2024 18:21:20 +0000 Subject: [PATCH 050/204] Bump fast-xml-parser and @aws-sdk/credential-providers Bumps [fast-xml-parser](https://github.com/NaturalIntelligence/fast-xml-parser) and [@aws-sdk/credential-providers](https://github.com/aws/aws-sdk-js-v3/tree/HEAD/packages/credential-providers). These dependencies needed to be updated together. Updates `fast-xml-parser` from 4.2.5 to 4.4.1 - [Release notes](https://github.com/NaturalIntelligence/fast-xml-parser/releases) - [Changelog](https://github.com/NaturalIntelligence/fast-xml-parser/blob/master/CHANGELOG.md) - [Commits](https://github.com/NaturalIntelligence/fast-xml-parser/compare/v4.2.5...v4.4.1) Updates `@aws-sdk/credential-providers` from 3.398.0 to 3.621.0 - [Release notes](https://github.com/aws/aws-sdk-js-v3/releases) - [Changelog](https://github.com/aws/aws-sdk-js-v3/blob/main/packages/credential-providers/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-js-v3/commits/v3.621.0/packages/credential-providers) --- updated-dependencies: - dependency-name: fast-xml-parser dependency-type: indirect - dependency-name: "@aws-sdk/credential-providers" dependency-type: indirect ... Signed-off-by: dependabot[bot] --- .../JavaScript/spliffy/package-lock.json | 3541 ++++++++++++----- 1 file changed, 2581 insertions(+), 960 deletions(-) diff --git a/frameworks/JavaScript/spliffy/package-lock.json b/frameworks/JavaScript/spliffy/package-lock.json index 40b146ce31c..114cddc45d1 100644 --- a/frameworks/JavaScript/spliffy/package-lock.json +++ b/frameworks/JavaScript/spliffy/package-lock.json @@ -4,986 +4,2619 @@ "lockfileVersion": 1, "requires": true, "dependencies": { - "@aws-crypto/crc32": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@aws-crypto/crc32/-/crc32-3.0.0.tgz", - "integrity": "sha512-IzSgsrxUcsrejQbPVilIKy16kAT52EwB6zSaI+M3xxIhKh5+aldEyvI+z6erM7TCLB2BJsFrtHjp6/4/sr+3dA==", - "optional": true, - "requires": { - "@aws-crypto/util": "^3.0.0", - "@aws-sdk/types": "^3.222.0", - "tslib": "^1.11.1" + "@aws-sdk/client-sso-oidc": { + "version": "3.621.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso-oidc/-/client-sso-oidc-3.621.0.tgz", + "integrity": "sha512-mMjk3mFUwV2Y68POf1BQMTF+F6qxt5tPu6daEUCNGC9Cenk3h2YXQQoS4/eSyYzuBiYk3vx49VgleRvdvkg8rg==", + "requires": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/core": "3.621.0", + "@aws-sdk/credential-provider-node": "3.621.0", + "@aws-sdk/middleware-host-header": "3.620.0", + "@aws-sdk/middleware-logger": "3.609.0", + "@aws-sdk/middleware-recursion-detection": "3.620.0", + "@aws-sdk/middleware-user-agent": "3.620.0", + "@aws-sdk/region-config-resolver": "3.614.0", + "@aws-sdk/types": "3.609.0", + "@aws-sdk/util-endpoints": "3.614.0", + "@aws-sdk/util-user-agent-browser": "3.609.0", + "@aws-sdk/util-user-agent-node": "3.614.0", + "@smithy/config-resolver": "^3.0.5", + "@smithy/core": "^2.3.1", + "@smithy/fetch-http-handler": "^3.2.4", + "@smithy/hash-node": "^3.0.3", + "@smithy/invalid-dependency": "^3.0.3", + "@smithy/middleware-content-length": "^3.0.5", + "@smithy/middleware-endpoint": "^3.1.0", + "@smithy/middleware-retry": "^3.0.13", + "@smithy/middleware-serde": "^3.0.3", + "@smithy/middleware-stack": "^3.0.3", + "@smithy/node-config-provider": "^3.1.4", + "@smithy/node-http-handler": "^3.1.4", + "@smithy/protocol-http": "^4.1.0", + "@smithy/smithy-client": "^3.1.11", + "@smithy/types": "^3.3.0", + "@smithy/url-parser": "^3.0.3", + "@smithy/util-base64": "^3.0.0", + "@smithy/util-body-length-browser": "^3.0.0", + "@smithy/util-body-length-node": "^3.0.0", + "@smithy/util-defaults-mode-browser": "^3.0.13", + "@smithy/util-defaults-mode-node": "^3.0.13", + "@smithy/util-endpoints": "^2.0.5", + "@smithy/util-middleware": "^3.0.3", + "@smithy/util-retry": "^3.0.3", + "@smithy/util-utf8": "^3.0.0", + "tslib": "^2.6.2" }, "dependencies": { - "tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "optional": true + "@aws-crypto/sha256-browser": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-browser/-/sha256-browser-5.2.0.tgz", + "integrity": "sha512-AXfN/lGotSQwu6HNcEsIASo7kWXZ5HYWvfOmSNKDsEqC4OashTp8alTmaz+F7TC2L083SFv5RdB+qU3Vs1kZqw==", + "requires": { + "@aws-crypto/sha256-js": "^5.2.0", + "@aws-crypto/supports-web-crypto": "^5.2.0", + "@aws-crypto/util": "^5.2.0", + "@aws-sdk/types": "^3.222.0", + "@aws-sdk/util-locate-window": "^3.0.0", + "@smithy/util-utf8": "^2.0.0", + "tslib": "^2.6.2" + }, + "dependencies": { + "@smithy/util-utf8": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-2.3.0.tgz", + "integrity": "sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A==", + "requires": { + "@smithy/util-buffer-from": "^2.2.0", + "tslib": "^2.6.2" + } + } + } + }, + "@aws-crypto/sha256-js": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-js/-/sha256-js-5.2.0.tgz", + "integrity": "sha512-FFQQyu7edu4ufvIZ+OadFpHHOt+eSTBaYaki44c+akjg7qZg9oOQeLlk77F6tSYqjDAFClrHJk9tMf0HdVyOvA==", + "requires": { + "@aws-crypto/util": "^5.2.0", + "@aws-sdk/types": "^3.222.0", + "tslib": "^2.6.2" + } + }, + "@aws-crypto/supports-web-crypto": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/supports-web-crypto/-/supports-web-crypto-5.2.0.tgz", + "integrity": "sha512-iAvUotm021kM33eCdNfwIN//F77/IADDSs58i+MDaOqFrVjZo9bAal0NK7HurRuWLLpF1iLX7gbWrjHjeo+YFg==", + "requires": { + "tslib": "^2.6.2" + } + }, + "@aws-crypto/util": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/util/-/util-5.2.0.tgz", + "integrity": "sha512-4RkU9EsI6ZpBve5fseQlGNUWKMa1RLPQ1dnjnQoe07ldfIzcsGb5hC5W0Dm7u423KWzawlrpbjXBrXCEv9zazQ==", + "requires": { + "@aws-sdk/types": "^3.222.0", + "@smithy/util-utf8": "^2.0.0", + "tslib": "^2.6.2" + }, + "dependencies": { + "@smithy/util-utf8": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-2.3.0.tgz", + "integrity": "sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A==", + "requires": { + "@smithy/util-buffer-from": "^2.2.0", + "tslib": "^2.6.2" + } + } + } + }, + "@aws-sdk/client-sso": { + "version": "3.621.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.621.0.tgz", + "integrity": "sha512-xpKfikN4u0BaUYZA9FGUMkkDmfoIP0Q03+A86WjqDWhcOoqNA1DkHsE4kZ+r064ifkPUfcNuUvlkVTEoBZoFjA==", + "requires": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/core": "3.621.0", + "@aws-sdk/middleware-host-header": "3.620.0", + "@aws-sdk/middleware-logger": "3.609.0", + "@aws-sdk/middleware-recursion-detection": "3.620.0", + "@aws-sdk/middleware-user-agent": "3.620.0", + "@aws-sdk/region-config-resolver": "3.614.0", + "@aws-sdk/types": "3.609.0", + "@aws-sdk/util-endpoints": "3.614.0", + "@aws-sdk/util-user-agent-browser": "3.609.0", + "@aws-sdk/util-user-agent-node": "3.614.0", + "@smithy/config-resolver": "^3.0.5", + "@smithy/core": "^2.3.1", + "@smithy/fetch-http-handler": "^3.2.4", + "@smithy/hash-node": "^3.0.3", + "@smithy/invalid-dependency": "^3.0.3", + "@smithy/middleware-content-length": "^3.0.5", + "@smithy/middleware-endpoint": "^3.1.0", + "@smithy/middleware-retry": "^3.0.13", + "@smithy/middleware-serde": "^3.0.3", + "@smithy/middleware-stack": "^3.0.3", + "@smithy/node-config-provider": "^3.1.4", + "@smithy/node-http-handler": "^3.1.4", + "@smithy/protocol-http": "^4.1.0", + "@smithy/smithy-client": "^3.1.11", + "@smithy/types": "^3.3.0", + "@smithy/url-parser": "^3.0.3", + "@smithy/util-base64": "^3.0.0", + "@smithy/util-body-length-browser": "^3.0.0", + "@smithy/util-body-length-node": "^3.0.0", + "@smithy/util-defaults-mode-browser": "^3.0.13", + "@smithy/util-defaults-mode-node": "^3.0.13", + "@smithy/util-endpoints": "^2.0.5", + "@smithy/util-middleware": "^3.0.3", + "@smithy/util-retry": "^3.0.3", + "@smithy/util-utf8": "^3.0.0", + "tslib": "^2.6.2" + } + }, + "@aws-sdk/credential-provider-env": { + "version": "3.620.1", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.620.1.tgz", + "integrity": "sha512-ExuILJ2qLW5ZO+rgkNRj0xiAipKT16Rk77buvPP8csR7kkCflT/gXTyzRe/uzIiETTxM7tr8xuO9MP/DQXqkfg==", + "requires": { + "@aws-sdk/types": "3.609.0", + "@smithy/property-provider": "^3.1.3", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + } + }, + "@aws-sdk/credential-provider-ini": { + "version": "3.621.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.621.0.tgz", + "integrity": "sha512-0EWVnSc+JQn5HLnF5Xv405M8n4zfdx9gyGdpnCmAmFqEDHA8LmBdxJdpUk1Ovp/I5oPANhjojxabIW5f1uU0RA==", + "requires": { + "@aws-sdk/credential-provider-env": "3.620.1", + "@aws-sdk/credential-provider-http": "3.621.0", + "@aws-sdk/credential-provider-process": "3.620.1", + "@aws-sdk/credential-provider-sso": "3.621.0", + "@aws-sdk/credential-provider-web-identity": "3.621.0", + "@aws-sdk/types": "3.609.0", + "@smithy/credential-provider-imds": "^3.2.0", + "@smithy/property-provider": "^3.1.3", + "@smithy/shared-ini-file-loader": "^3.1.4", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + } + }, + "@aws-sdk/credential-provider-node": { + "version": "3.621.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.621.0.tgz", + "integrity": "sha512-4JqpccUgz5Snanpt2+53hbOBbJQrSFq7E1sAAbgY6BKVQUsW5qyXqnjvSF32kDeKa5JpBl3bBWLZl04IadcPHw==", + "requires": { + "@aws-sdk/credential-provider-env": "3.620.1", + "@aws-sdk/credential-provider-http": "3.621.0", + "@aws-sdk/credential-provider-ini": "3.621.0", + "@aws-sdk/credential-provider-process": "3.620.1", + "@aws-sdk/credential-provider-sso": "3.621.0", + "@aws-sdk/credential-provider-web-identity": "3.621.0", + "@aws-sdk/types": "3.609.0", + "@smithy/credential-provider-imds": "^3.2.0", + "@smithy/property-provider": "^3.1.3", + "@smithy/shared-ini-file-loader": "^3.1.4", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + } + }, + "@aws-sdk/credential-provider-process": { + "version": "3.620.1", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.620.1.tgz", + "integrity": "sha512-hWqFMidqLAkaV9G460+1at6qa9vySbjQKKc04p59OT7lZ5cO5VH5S4aI05e+m4j364MBROjjk2ugNvfNf/8ILg==", + "requires": { + "@aws-sdk/types": "3.609.0", + "@smithy/property-provider": "^3.1.3", + "@smithy/shared-ini-file-loader": "^3.1.4", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + } + }, + "@aws-sdk/credential-provider-sso": { + "version": "3.621.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.621.0.tgz", + "integrity": "sha512-Kza0jcFeA/GEL6xJlzR2KFf1PfZKMFnxfGzJzl5yN7EjoGdMijl34KaRyVnfRjnCWcsUpBWKNIDk9WZVMY9yiw==", + "requires": { + "@aws-sdk/client-sso": "3.621.0", + "@aws-sdk/token-providers": "3.614.0", + "@aws-sdk/types": "3.609.0", + "@smithy/property-provider": "^3.1.3", + "@smithy/shared-ini-file-loader": "^3.1.4", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + } + }, + "@aws-sdk/credential-provider-web-identity": { + "version": "3.621.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.621.0.tgz", + "integrity": "sha512-w7ASSyfNvcx7+bYGep3VBgC3K6vEdLmlpjT7nSIHxxQf+WSdvy+HynwJosrpZax0sK5q0D1Jpn/5q+r5lwwW6w==", + "requires": { + "@aws-sdk/types": "3.609.0", + "@smithy/property-provider": "^3.1.3", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + } + }, + "@aws-sdk/middleware-host-header": { + "version": "3.620.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.620.0.tgz", + "integrity": "sha512-VMtPEZwqYrII/oUkffYsNWY9PZ9xpNJpMgmyU0rlDQ25O1c0Hk3fJmZRe6pEkAJ0omD7kLrqGl1DUjQVxpd/Rg==", + "requires": { + "@aws-sdk/types": "3.609.0", + "@smithy/protocol-http": "^4.1.0", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + } + }, + "@aws-sdk/middleware-logger": { + "version": "3.609.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.609.0.tgz", + "integrity": "sha512-S62U2dy4jMDhDFDK5gZ4VxFdWzCtLzwbYyFZx2uvPYTECkepLUfzLic2BHg2Qvtu4QjX+oGE3P/7fwaGIsGNuQ==", + "requires": { + "@aws-sdk/types": "3.609.0", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + } + }, + "@aws-sdk/middleware-recursion-detection": { + "version": "3.620.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.620.0.tgz", + "integrity": "sha512-nh91S7aGK3e/o1ck64sA/CyoFw+gAYj2BDOnoNa6ouyCrVJED96ZXWbhye/fz9SgmNUZR2g7GdVpiLpMKZoI5w==", + "requires": { + "@aws-sdk/types": "3.609.0", + "@smithy/protocol-http": "^4.1.0", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + } + }, + "@aws-sdk/middleware-user-agent": { + "version": "3.620.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.620.0.tgz", + "integrity": "sha512-bvS6etn+KsuL32ubY5D3xNof1qkenpbJXf/ugGXbg0n98DvDFQ/F+SMLxHgbnER5dsKYchNnhmtI6/FC3HFu/A==", + "requires": { + "@aws-sdk/types": "3.609.0", + "@aws-sdk/util-endpoints": "3.614.0", + "@smithy/protocol-http": "^4.1.0", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + } + }, + "@aws-sdk/token-providers": { + "version": "3.614.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.614.0.tgz", + "integrity": "sha512-okItqyY6L9IHdxqs+Z116y5/nda7rHxLvROxtAJdLavWTYDydxrZstImNgGWTeVdmc0xX2gJCI77UYUTQWnhRw==", + "requires": { + "@aws-sdk/types": "3.609.0", + "@smithy/property-provider": "^3.1.3", + "@smithy/shared-ini-file-loader": "^3.1.4", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + } + }, + "@aws-sdk/types": { + "version": "3.609.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.609.0.tgz", + "integrity": "sha512-+Tqnh9w0h2LcrUsdXyT1F8mNhXz+tVYBtP19LpeEGntmvHwa2XzvLUCWpoIAIVsHp5+HdB2X9Sn0KAtmbFXc2Q==", + "requires": { + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + } + }, + "@aws-sdk/util-endpoints": { + "version": "3.614.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.614.0.tgz", + "integrity": "sha512-wK2cdrXHH4oz4IomV/yrGkftU9A+ITB6nFL+rxxyO78is2ifHJpFdV4aqk4LSkXYPi6CXWNru/Dqc7yiKXgJPw==", + "requires": { + "@aws-sdk/types": "3.609.0", + "@smithy/types": "^3.3.0", + "@smithy/util-endpoints": "^2.0.5", + "tslib": "^2.6.2" + } + }, + "@aws-sdk/util-user-agent-browser": { + "version": "3.609.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.609.0.tgz", + "integrity": "sha512-fojPU+mNahzQ0YHYBsx0ZIhmMA96H+ZIZ665ObU9tl+SGdbLneVZVikGve+NmHTQwHzwkFsZYYnVKAkreJLAtA==", + "requires": { + "@aws-sdk/types": "3.609.0", + "@smithy/types": "^3.3.0", + "bowser": "^2.11.0", + "tslib": "^2.6.2" + } + }, + "@aws-sdk/util-user-agent-node": { + "version": "3.614.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.614.0.tgz", + "integrity": "sha512-15ElZT88peoHnq5TEoEtZwoXTXRxNrk60TZNdpl/TUBJ5oNJ9Dqb5Z4ryb8ofN6nm9aFf59GVAerFDz8iUoHBA==", + "requires": { + "@aws-sdk/types": "3.609.0", + "@smithy/node-config-provider": "^3.1.4", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + } + }, + "@smithy/abort-controller": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@smithy/abort-controller/-/abort-controller-3.1.1.tgz", + "integrity": "sha512-MBJBiidoe+0cTFhyxT8g+9g7CeVccLM0IOKKUMCNQ1CNMJ/eIfoo0RTfVrXOONEI1UCN1W+zkiHSbzUNE9dZtQ==", + "requires": { + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + } + }, + "@smithy/config-resolver": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@smithy/config-resolver/-/config-resolver-3.0.5.tgz", + "integrity": "sha512-SkW5LxfkSI1bUC74OtfBbdz+grQXYiPYolyu8VfpLIjEoN/sHVBlLeGXMQ1vX4ejkgfv6sxVbQJ32yF2cl1veA==", + "requires": { + "@smithy/node-config-provider": "^3.1.4", + "@smithy/types": "^3.3.0", + "@smithy/util-config-provider": "^3.0.0", + "@smithy/util-middleware": "^3.0.3", + "tslib": "^2.6.2" + } + }, + "@smithy/credential-provider-imds": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/@smithy/credential-provider-imds/-/credential-provider-imds-3.2.0.tgz", + "integrity": "sha512-0SCIzgd8LYZ9EJxUjLXBmEKSZR/P/w6l7Rz/pab9culE/RWuqelAKGJvn5qUOl8BgX8Yj5HWM50A5hiB/RzsgA==", + "requires": { + "@smithy/node-config-provider": "^3.1.4", + "@smithy/property-provider": "^3.1.3", + "@smithy/types": "^3.3.0", + "@smithy/url-parser": "^3.0.3", + "tslib": "^2.6.2" + } + }, + "@smithy/fetch-http-handler": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-3.2.4.tgz", + "integrity": "sha512-kBprh5Gs5h7ug4nBWZi1FZthdqSM+T7zMmsZxx0IBvWUn7dK3diz2SHn7Bs4dQGFDk8plDv375gzenDoNwrXjg==", + "requires": { + "@smithy/protocol-http": "^4.1.0", + "@smithy/querystring-builder": "^3.0.3", + "@smithy/types": "^3.3.0", + "@smithy/util-base64": "^3.0.0", + "tslib": "^2.6.2" + } + }, + "@smithy/hash-node": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@smithy/hash-node/-/hash-node-3.0.3.tgz", + "integrity": "sha512-2ctBXpPMG+B3BtWSGNnKELJ7SH9e4TNefJS0cd2eSkOOROeBnnVBnAy9LtJ8tY4vUEoe55N4CNPxzbWvR39iBw==", + "requires": { + "@smithy/types": "^3.3.0", + "@smithy/util-buffer-from": "^3.0.0", + "@smithy/util-utf8": "^3.0.0", + "tslib": "^2.6.2" + }, + "dependencies": { + "@smithy/is-array-buffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-3.0.0.tgz", + "integrity": "sha512-+Fsu6Q6C4RSJiy81Y8eApjEB5gVtM+oFKTffg+jSuwtvomJJrhUJBu2zS8wjXSgH/g1MKEWrzyChTBe6clb5FQ==", + "requires": { + "tslib": "^2.6.2" + } + }, + "@smithy/util-buffer-from": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-3.0.0.tgz", + "integrity": "sha512-aEOHCgq5RWFbP+UDPvPot26EJHjOC+bRgse5A8V3FSShqd5E5UN4qc7zkwsvJPPAVsf73QwYcHN1/gt/rtLwQA==", + "requires": { + "@smithy/is-array-buffer": "^3.0.0", + "tslib": "^2.6.2" + } + } + } + }, + "@smithy/invalid-dependency": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@smithy/invalid-dependency/-/invalid-dependency-3.0.3.tgz", + "integrity": "sha512-ID1eL/zpDULmHJbflb864k72/SNOZCADRc9i7Exq3RUNJw6raWUSlFEQ+3PX3EYs++bTxZB2dE9mEHTQLv61tw==", + "requires": { + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + } + }, + "@smithy/is-array-buffer": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-2.2.0.tgz", + "integrity": "sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA==", + "requires": { + "tslib": "^2.6.2" + } + }, + "@smithy/middleware-content-length": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@smithy/middleware-content-length/-/middleware-content-length-3.0.5.tgz", + "integrity": "sha512-ILEzC2eyxx6ncej3zZSwMpB5RJ0zuqH7eMptxC4KN3f+v9bqT8ohssKbhNR78k/2tWW+KS5Spw+tbPF4Ejyqvw==", + "requires": { + "@smithy/protocol-http": "^4.1.0", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + } + }, + "@smithy/middleware-endpoint": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@smithy/middleware-endpoint/-/middleware-endpoint-3.1.0.tgz", + "integrity": "sha512-5y5aiKCEwg9TDPB4yFE7H6tYvGFf1OJHNczeY10/EFF8Ir8jZbNntQJxMWNfeQjC1mxPsaQ6mR9cvQbf+0YeMw==", + "requires": { + "@smithy/middleware-serde": "^3.0.3", + "@smithy/node-config-provider": "^3.1.4", + "@smithy/shared-ini-file-loader": "^3.1.4", + "@smithy/types": "^3.3.0", + "@smithy/url-parser": "^3.0.3", + "@smithy/util-middleware": "^3.0.3", + "tslib": "^2.6.2" + } + }, + "@smithy/middleware-retry": { + "version": "3.0.13", + "resolved": "https://registry.npmjs.org/@smithy/middleware-retry/-/middleware-retry-3.0.13.tgz", + "integrity": "sha512-zvCLfaRYCaUmjbF2yxShGZdolSHft7NNCTA28HVN9hKcEbOH+g5irr1X9s+in8EpambclGnevZY4A3lYpvDCFw==", + "requires": { + "@smithy/node-config-provider": "^3.1.4", + "@smithy/protocol-http": "^4.1.0", + "@smithy/service-error-classification": "^3.0.3", + "@smithy/smithy-client": "^3.1.11", + "@smithy/types": "^3.3.0", + "@smithy/util-middleware": "^3.0.3", + "@smithy/util-retry": "^3.0.3", + "tslib": "^2.6.2", + "uuid": "^9.0.1" + } + }, + "@smithy/middleware-serde": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@smithy/middleware-serde/-/middleware-serde-3.0.3.tgz", + "integrity": "sha512-puUbyJQBcg9eSErFXjKNiGILJGtiqmuuNKEYNYfUD57fUl4i9+mfmThtQhvFXU0hCVG0iEJhvQUipUf+/SsFdA==", + "requires": { + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + } + }, + "@smithy/middleware-stack": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@smithy/middleware-stack/-/middleware-stack-3.0.3.tgz", + "integrity": "sha512-r4klY9nFudB0r9UdSMaGSyjyQK5adUyPnQN/ZM6M75phTxOdnc/AhpvGD1fQUvgmqjQEBGCwpnPbDm8pH5PapA==", + "requires": { + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + } + }, + "@smithy/node-config-provider": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/@smithy/node-config-provider/-/node-config-provider-3.1.4.tgz", + "integrity": "sha512-YvnElQy8HR4vDcAjoy7Xkx9YT8xZP4cBXcbJSgm/kxmiQu08DwUwj8rkGnyoJTpfl/3xYHH+d8zE+eHqoDCSdQ==", + "requires": { + "@smithy/property-provider": "^3.1.3", + "@smithy/shared-ini-file-loader": "^3.1.4", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + } + }, + "@smithy/node-http-handler": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-3.1.4.tgz", + "integrity": "sha512-+UmxgixgOr/yLsUxcEKGH0fMNVteJFGkmRltYFHnBMlogyFdpzn2CwqWmxOrfJELhV34v0WSlaqG1UtE1uXlJg==", + "requires": { + "@smithy/abort-controller": "^3.1.1", + "@smithy/protocol-http": "^4.1.0", + "@smithy/querystring-builder": "^3.0.3", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + } + }, + "@smithy/property-provider": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/@smithy/property-provider/-/property-provider-3.1.3.tgz", + "integrity": "sha512-zahyOVR9Q4PEoguJ/NrFP4O7SMAfYO1HLhB18M+q+Z4KFd4V2obiMnlVoUFzFLSPeVt1POyNWneHHrZaTMoc/g==", + "requires": { + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + } + }, + "@smithy/protocol-http": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-4.1.0.tgz", + "integrity": "sha512-dPVoHYQ2wcHooGXg3LQisa1hH0e4y0pAddPMeeUPipI1tEOqL6A4N0/G7abeq+K8wrwSgjk4C0wnD1XZpJm5aA==", + "requires": { + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + } + }, + "@smithy/querystring-builder": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@smithy/querystring-builder/-/querystring-builder-3.0.3.tgz", + "integrity": "sha512-vyWckeUeesFKzCDaRwWLUA1Xym9McaA6XpFfAK5qI9DKJ4M33ooQGqvM4J+LalH4u/Dq9nFiC8U6Qn1qi0+9zw==", + "requires": { + "@smithy/types": "^3.3.0", + "@smithy/util-uri-escape": "^3.0.0", + "tslib": "^2.6.2" + } + }, + "@smithy/querystring-parser": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@smithy/querystring-parser/-/querystring-parser-3.0.3.tgz", + "integrity": "sha512-zahM1lQv2YjmznnfQsWbYojFe55l0SLG/988brlLv1i8z3dubloLF+75ATRsqPBboUXsW6I9CPGE5rQgLfY0vQ==", + "requires": { + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + } + }, + "@smithy/service-error-classification": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@smithy/service-error-classification/-/service-error-classification-3.0.3.tgz", + "integrity": "sha512-Jn39sSl8cim/VlkLsUhRFq/dKDnRUFlfRkvhOJaUbLBXUsLRLNf9WaxDv/z9BjuQ3A6k/qE8af1lsqcwm7+DaQ==", + "requires": { + "@smithy/types": "^3.3.0" + } + }, + "@smithy/shared-ini-file-loader": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/@smithy/shared-ini-file-loader/-/shared-ini-file-loader-3.1.4.tgz", + "integrity": "sha512-qMxS4hBGB8FY2GQqshcRUy1K6k8aBWP5vwm8qKkCT3A9K2dawUwOIJfqh9Yste/Bl0J2lzosVyrXDj68kLcHXQ==", + "requires": { + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + } + }, + "@smithy/smithy-client": { + "version": "3.1.11", + "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-3.1.11.tgz", + "integrity": "sha512-l0BpyYkciNyMaS+PnFFz4aO5sBcXvGLoJd7mX9xrMBIm2nIQBVvYgp2ZpPDMzwjKCavsXu06iuCm0F6ZJZc6yQ==", + "requires": { + "@smithy/middleware-endpoint": "^3.1.0", + "@smithy/middleware-stack": "^3.0.3", + "@smithy/protocol-http": "^4.1.0", + "@smithy/types": "^3.3.0", + "@smithy/util-stream": "^3.1.3", + "tslib": "^2.6.2" + } + }, + "@smithy/types": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-3.3.0.tgz", + "integrity": "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA==", + "requires": { + "tslib": "^2.6.2" + } + }, + "@smithy/url-parser": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@smithy/url-parser/-/url-parser-3.0.3.tgz", + "integrity": "sha512-pw3VtZtX2rg+s6HMs6/+u9+hu6oY6U7IohGhVNnjbgKy86wcIsSZwgHrFR+t67Uyxvp4Xz3p3kGXXIpTNisq8A==", + "requires": { + "@smithy/querystring-parser": "^3.0.3", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + } + }, + "@smithy/util-base64": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-base64/-/util-base64-3.0.0.tgz", + "integrity": "sha512-Kxvoh5Qtt0CDsfajiZOCpJxgtPHXOKwmM+Zy4waD43UoEMA+qPxxa98aE/7ZhdnBFZFXMOiBR5xbcaMhLtznQQ==", + "requires": { + "@smithy/util-buffer-from": "^3.0.0", + "@smithy/util-utf8": "^3.0.0", + "tslib": "^2.6.2" + }, + "dependencies": { + "@smithy/is-array-buffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-3.0.0.tgz", + "integrity": "sha512-+Fsu6Q6C4RSJiy81Y8eApjEB5gVtM+oFKTffg+jSuwtvomJJrhUJBu2zS8wjXSgH/g1MKEWrzyChTBe6clb5FQ==", + "requires": { + "tslib": "^2.6.2" + } + }, + "@smithy/util-buffer-from": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-3.0.0.tgz", + "integrity": "sha512-aEOHCgq5RWFbP+UDPvPot26EJHjOC+bRgse5A8V3FSShqd5E5UN4qc7zkwsvJPPAVsf73QwYcHN1/gt/rtLwQA==", + "requires": { + "@smithy/is-array-buffer": "^3.0.0", + "tslib": "^2.6.2" + } + } + } + }, + "@smithy/util-body-length-browser": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-body-length-browser/-/util-body-length-browser-3.0.0.tgz", + "integrity": "sha512-cbjJs2A1mLYmqmyVl80uoLTJhAcfzMOyPgjwAYusWKMdLeNtzmMz9YxNl3/jRLoxSS3wkqkf0jwNdtXWtyEBaQ==", + "requires": { + "tslib": "^2.6.2" + } + }, + "@smithy/util-body-length-node": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-body-length-node/-/util-body-length-node-3.0.0.tgz", + "integrity": "sha512-Tj7pZ4bUloNUP6PzwhN7K386tmSmEET9QtQg0TgdNOnxhZvCssHji+oZTUIuzxECRfG8rdm2PMw2WCFs6eIYkA==", + "requires": { + "tslib": "^2.6.2" + } + }, + "@smithy/util-buffer-from": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-2.2.0.tgz", + "integrity": "sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA==", + "requires": { + "@smithy/is-array-buffer": "^2.2.0", + "tslib": "^2.6.2" + } + }, + "@smithy/util-config-provider": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-config-provider/-/util-config-provider-3.0.0.tgz", + "integrity": "sha512-pbjk4s0fwq3Di/ANL+rCvJMKM5bzAQdE5S/6RL5NXgMExFAi6UgQMPOm5yPaIWPpr+EOXKXRonJ3FoxKf4mCJQ==", + "requires": { + "tslib": "^2.6.2" + } + }, + "@smithy/util-defaults-mode-browser": { + "version": "3.0.13", + "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-3.0.13.tgz", + "integrity": "sha512-ZIRSUsnnMRStOP6OKtW+gCSiVFkwnfQF2xtf32QKAbHR6ACjhbAybDvry+3L5qQYdh3H6+7yD/AiUE45n8mTTw==", + "requires": { + "@smithy/property-provider": "^3.1.3", + "@smithy/smithy-client": "^3.1.11", + "@smithy/types": "^3.3.0", + "bowser": "^2.11.0", + "tslib": "^2.6.2" + } + }, + "@smithy/util-defaults-mode-node": { + "version": "3.0.13", + "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-3.0.13.tgz", + "integrity": "sha512-voUa8TFJGfD+U12tlNNLCDlXibt9vRdNzRX45Onk/WxZe7TS+hTOZouEZRa7oARGicdgeXvt1A0W45qLGYdy+g==", + "requires": { + "@smithy/config-resolver": "^3.0.5", + "@smithy/credential-provider-imds": "^3.2.0", + "@smithy/node-config-provider": "^3.1.4", + "@smithy/property-provider": "^3.1.3", + "@smithy/smithy-client": "^3.1.11", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + } + }, + "@smithy/util-hex-encoding": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-hex-encoding/-/util-hex-encoding-3.0.0.tgz", + "integrity": "sha512-eFndh1WEK5YMUYvy3lPlVmYY/fZcQE1D8oSf41Id2vCeIkKJXPcYDCZD+4+xViI6b1XSd7tE+s5AmXzz5ilabQ==", + "requires": { + "tslib": "^2.6.2" + } + }, + "@smithy/util-middleware": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@smithy/util-middleware/-/util-middleware-3.0.3.tgz", + "integrity": "sha512-l+StyYYK/eO3DlVPbU+4Bi06Jjal+PFLSMmlWM1BEwyLxZ3aKkf1ROnoIakfaA7mC6uw3ny7JBkau4Yc+5zfWw==", + "requires": { + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + } + }, + "@smithy/util-retry": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@smithy/util-retry/-/util-retry-3.0.3.tgz", + "integrity": "sha512-AFw+hjpbtVApzpNDhbjNG5NA3kyoMs7vx0gsgmlJF4s+yz1Zlepde7J58zpIRIsdjc+emhpAITxA88qLkPF26w==", + "requires": { + "@smithy/service-error-classification": "^3.0.3", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + } + }, + "@smithy/util-stream": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/@smithy/util-stream/-/util-stream-3.1.3.tgz", + "integrity": "sha512-FIv/bRhIlAxC0U7xM1BCnF2aDRPq0UaelqBHkM2lsCp26mcBbgI0tCVTv+jGdsQLUmAMybua/bjDsSu8RQHbmw==", + "requires": { + "@smithy/fetch-http-handler": "^3.2.4", + "@smithy/node-http-handler": "^3.1.4", + "@smithy/types": "^3.3.0", + "@smithy/util-base64": "^3.0.0", + "@smithy/util-buffer-from": "^3.0.0", + "@smithy/util-hex-encoding": "^3.0.0", + "@smithy/util-utf8": "^3.0.0", + "tslib": "^2.6.2" + }, + "dependencies": { + "@smithy/is-array-buffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-3.0.0.tgz", + "integrity": "sha512-+Fsu6Q6C4RSJiy81Y8eApjEB5gVtM+oFKTffg+jSuwtvomJJrhUJBu2zS8wjXSgH/g1MKEWrzyChTBe6clb5FQ==", + "requires": { + "tslib": "^2.6.2" + } + }, + "@smithy/util-buffer-from": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-3.0.0.tgz", + "integrity": "sha512-aEOHCgq5RWFbP+UDPvPot26EJHjOC+bRgse5A8V3FSShqd5E5UN4qc7zkwsvJPPAVsf73QwYcHN1/gt/rtLwQA==", + "requires": { + "@smithy/is-array-buffer": "^3.0.0", + "tslib": "^2.6.2" + } + } + } + }, + "@smithy/util-uri-escape": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-uri-escape/-/util-uri-escape-3.0.0.tgz", + "integrity": "sha512-LqR7qYLgZTD7nWLBecUi4aqolw8Mhza9ArpNEQ881MJJIU2sE5iHCK6TdyqqzcDLy0OPe10IY4T8ctVdtynubg==", + "requires": { + "tslib": "^2.6.2" + } + }, + "@smithy/util-utf8": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-3.0.0.tgz", + "integrity": "sha512-rUeT12bxFnplYDe815GXbq/oixEGHfRFFtcTF3YdDi/JaENIM6aSYYLJydG83UNzLXeRI5K8abYd/8Sp/QM0kA==", + "requires": { + "@smithy/util-buffer-from": "^3.0.0", + "tslib": "^2.6.2" + }, + "dependencies": { + "@smithy/is-array-buffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-3.0.0.tgz", + "integrity": "sha512-+Fsu6Q6C4RSJiy81Y8eApjEB5gVtM+oFKTffg+jSuwtvomJJrhUJBu2zS8wjXSgH/g1MKEWrzyChTBe6clb5FQ==", + "requires": { + "tslib": "^2.6.2" + } + }, + "@smithy/util-buffer-from": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-3.0.0.tgz", + "integrity": "sha512-aEOHCgq5RWFbP+UDPvPot26EJHjOC+bRgse5A8V3FSShqd5E5UN4qc7zkwsvJPPAVsf73QwYcHN1/gt/rtLwQA==", + "requires": { + "@smithy/is-array-buffer": "^3.0.0", + "tslib": "^2.6.2" + } + } + } + }, + "uuid": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", + "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==" } } }, - "@aws-crypto/ie11-detection": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@aws-crypto/ie11-detection/-/ie11-detection-3.0.0.tgz", - "integrity": "sha512-341lBBkiY1DfDNKai/wXM3aujNBkXR7tq1URPQDL9wi3AUbI80NR74uF1TXHMm7po1AcnFk8iu2S2IeU/+/A+Q==", - "optional": true, - "requires": { - "tslib": "^1.11.1" + "@aws-sdk/core": { + "version": "3.621.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.621.0.tgz", + "integrity": "sha512-CtOwWmDdEiINkGXD93iGfXjN0WmCp9l45cDWHHGa8lRgEDyhuL7bwd/pH5aSzj0j8SiQBG2k0S7DHbd5RaqvbQ==", + "requires": { + "@smithy/core": "^2.3.1", + "@smithy/node-config-provider": "^3.1.4", + "@smithy/protocol-http": "^4.1.0", + "@smithy/signature-v4": "^4.1.0", + "@smithy/smithy-client": "^3.1.11", + "@smithy/types": "^3.3.0", + "@smithy/util-middleware": "^3.0.3", + "fast-xml-parser": "4.4.1", + "tslib": "^2.6.2" }, "dependencies": { - "tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "optional": true + "@smithy/abort-controller": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@smithy/abort-controller/-/abort-controller-3.1.1.tgz", + "integrity": "sha512-MBJBiidoe+0cTFhyxT8g+9g7CeVccLM0IOKKUMCNQ1CNMJ/eIfoo0RTfVrXOONEI1UCN1W+zkiHSbzUNE9dZtQ==", + "requires": { + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + } + }, + "@smithy/fetch-http-handler": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-3.2.4.tgz", + "integrity": "sha512-kBprh5Gs5h7ug4nBWZi1FZthdqSM+T7zMmsZxx0IBvWUn7dK3diz2SHn7Bs4dQGFDk8plDv375gzenDoNwrXjg==", + "requires": { + "@smithy/protocol-http": "^4.1.0", + "@smithy/querystring-builder": "^3.0.3", + "@smithy/types": "^3.3.0", + "@smithy/util-base64": "^3.0.0", + "tslib": "^2.6.2" + } + }, + "@smithy/is-array-buffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-3.0.0.tgz", + "integrity": "sha512-+Fsu6Q6C4RSJiy81Y8eApjEB5gVtM+oFKTffg+jSuwtvomJJrhUJBu2zS8wjXSgH/g1MKEWrzyChTBe6clb5FQ==", + "requires": { + "tslib": "^2.6.2" + } + }, + "@smithy/middleware-endpoint": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@smithy/middleware-endpoint/-/middleware-endpoint-3.1.0.tgz", + "integrity": "sha512-5y5aiKCEwg9TDPB4yFE7H6tYvGFf1OJHNczeY10/EFF8Ir8jZbNntQJxMWNfeQjC1mxPsaQ6mR9cvQbf+0YeMw==", + "requires": { + "@smithy/middleware-serde": "^3.0.3", + "@smithy/node-config-provider": "^3.1.4", + "@smithy/shared-ini-file-loader": "^3.1.4", + "@smithy/types": "^3.3.0", + "@smithy/url-parser": "^3.0.3", + "@smithy/util-middleware": "^3.0.3", + "tslib": "^2.6.2" + } + }, + "@smithy/middleware-serde": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@smithy/middleware-serde/-/middleware-serde-3.0.3.tgz", + "integrity": "sha512-puUbyJQBcg9eSErFXjKNiGILJGtiqmuuNKEYNYfUD57fUl4i9+mfmThtQhvFXU0hCVG0iEJhvQUipUf+/SsFdA==", + "requires": { + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + } + }, + "@smithy/middleware-stack": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@smithy/middleware-stack/-/middleware-stack-3.0.3.tgz", + "integrity": "sha512-r4klY9nFudB0r9UdSMaGSyjyQK5adUyPnQN/ZM6M75phTxOdnc/AhpvGD1fQUvgmqjQEBGCwpnPbDm8pH5PapA==", + "requires": { + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + } + }, + "@smithy/node-config-provider": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/@smithy/node-config-provider/-/node-config-provider-3.1.4.tgz", + "integrity": "sha512-YvnElQy8HR4vDcAjoy7Xkx9YT8xZP4cBXcbJSgm/kxmiQu08DwUwj8rkGnyoJTpfl/3xYHH+d8zE+eHqoDCSdQ==", + "requires": { + "@smithy/property-provider": "^3.1.3", + "@smithy/shared-ini-file-loader": "^3.1.4", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + } + }, + "@smithy/node-http-handler": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-3.1.4.tgz", + "integrity": "sha512-+UmxgixgOr/yLsUxcEKGH0fMNVteJFGkmRltYFHnBMlogyFdpzn2CwqWmxOrfJELhV34v0WSlaqG1UtE1uXlJg==", + "requires": { + "@smithy/abort-controller": "^3.1.1", + "@smithy/protocol-http": "^4.1.0", + "@smithy/querystring-builder": "^3.0.3", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + } + }, + "@smithy/property-provider": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/@smithy/property-provider/-/property-provider-3.1.3.tgz", + "integrity": "sha512-zahyOVR9Q4PEoguJ/NrFP4O7SMAfYO1HLhB18M+q+Z4KFd4V2obiMnlVoUFzFLSPeVt1POyNWneHHrZaTMoc/g==", + "requires": { + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + } + }, + "@smithy/protocol-http": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-4.1.0.tgz", + "integrity": "sha512-dPVoHYQ2wcHooGXg3LQisa1hH0e4y0pAddPMeeUPipI1tEOqL6A4N0/G7abeq+K8wrwSgjk4C0wnD1XZpJm5aA==", + "requires": { + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + } + }, + "@smithy/querystring-builder": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@smithy/querystring-builder/-/querystring-builder-3.0.3.tgz", + "integrity": "sha512-vyWckeUeesFKzCDaRwWLUA1Xym9McaA6XpFfAK5qI9DKJ4M33ooQGqvM4J+LalH4u/Dq9nFiC8U6Qn1qi0+9zw==", + "requires": { + "@smithy/types": "^3.3.0", + "@smithy/util-uri-escape": "^3.0.0", + "tslib": "^2.6.2" + } + }, + "@smithy/querystring-parser": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@smithy/querystring-parser/-/querystring-parser-3.0.3.tgz", + "integrity": "sha512-zahM1lQv2YjmznnfQsWbYojFe55l0SLG/988brlLv1i8z3dubloLF+75ATRsqPBboUXsW6I9CPGE5rQgLfY0vQ==", + "requires": { + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + } + }, + "@smithy/shared-ini-file-loader": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/@smithy/shared-ini-file-loader/-/shared-ini-file-loader-3.1.4.tgz", + "integrity": "sha512-qMxS4hBGB8FY2GQqshcRUy1K6k8aBWP5vwm8qKkCT3A9K2dawUwOIJfqh9Yste/Bl0J2lzosVyrXDj68kLcHXQ==", + "requires": { + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + } + }, + "@smithy/signature-v4": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@smithy/signature-v4/-/signature-v4-4.1.0.tgz", + "integrity": "sha512-aRryp2XNZeRcOtuJoxjydO6QTaVhxx/vjaR+gx7ZjaFgrgPRyZ3HCTbfwqYj6ZWEBHkCSUfcaymKPURaByukag==", + "requires": { + "@smithy/is-array-buffer": "^3.0.0", + "@smithy/protocol-http": "^4.1.0", + "@smithy/types": "^3.3.0", + "@smithy/util-hex-encoding": "^3.0.0", + "@smithy/util-middleware": "^3.0.3", + "@smithy/util-uri-escape": "^3.0.0", + "@smithy/util-utf8": "^3.0.0", + "tslib": "^2.6.2" + } + }, + "@smithy/smithy-client": { + "version": "3.1.11", + "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-3.1.11.tgz", + "integrity": "sha512-l0BpyYkciNyMaS+PnFFz4aO5sBcXvGLoJd7mX9xrMBIm2nIQBVvYgp2ZpPDMzwjKCavsXu06iuCm0F6ZJZc6yQ==", + "requires": { + "@smithy/middleware-endpoint": "^3.1.0", + "@smithy/middleware-stack": "^3.0.3", + "@smithy/protocol-http": "^4.1.0", + "@smithy/types": "^3.3.0", + "@smithy/util-stream": "^3.1.3", + "tslib": "^2.6.2" + } + }, + "@smithy/types": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-3.3.0.tgz", + "integrity": "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA==", + "requires": { + "tslib": "^2.6.2" + } + }, + "@smithy/url-parser": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@smithy/url-parser/-/url-parser-3.0.3.tgz", + "integrity": "sha512-pw3VtZtX2rg+s6HMs6/+u9+hu6oY6U7IohGhVNnjbgKy86wcIsSZwgHrFR+t67Uyxvp4Xz3p3kGXXIpTNisq8A==", + "requires": { + "@smithy/querystring-parser": "^3.0.3", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + } + }, + "@smithy/util-base64": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-base64/-/util-base64-3.0.0.tgz", + "integrity": "sha512-Kxvoh5Qtt0CDsfajiZOCpJxgtPHXOKwmM+Zy4waD43UoEMA+qPxxa98aE/7ZhdnBFZFXMOiBR5xbcaMhLtznQQ==", + "requires": { + "@smithy/util-buffer-from": "^3.0.0", + "@smithy/util-utf8": "^3.0.0", + "tslib": "^2.6.2" + } + }, + "@smithy/util-buffer-from": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-3.0.0.tgz", + "integrity": "sha512-aEOHCgq5RWFbP+UDPvPot26EJHjOC+bRgse5A8V3FSShqd5E5UN4qc7zkwsvJPPAVsf73QwYcHN1/gt/rtLwQA==", + "requires": { + "@smithy/is-array-buffer": "^3.0.0", + "tslib": "^2.6.2" + } + }, + "@smithy/util-hex-encoding": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-hex-encoding/-/util-hex-encoding-3.0.0.tgz", + "integrity": "sha512-eFndh1WEK5YMUYvy3lPlVmYY/fZcQE1D8oSf41Id2vCeIkKJXPcYDCZD+4+xViI6b1XSd7tE+s5AmXzz5ilabQ==", + "requires": { + "tslib": "^2.6.2" + } + }, + "@smithy/util-middleware": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@smithy/util-middleware/-/util-middleware-3.0.3.tgz", + "integrity": "sha512-l+StyYYK/eO3DlVPbU+4Bi06Jjal+PFLSMmlWM1BEwyLxZ3aKkf1ROnoIakfaA7mC6uw3ny7JBkau4Yc+5zfWw==", + "requires": { + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + } + }, + "@smithy/util-stream": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/@smithy/util-stream/-/util-stream-3.1.3.tgz", + "integrity": "sha512-FIv/bRhIlAxC0U7xM1BCnF2aDRPq0UaelqBHkM2lsCp26mcBbgI0tCVTv+jGdsQLUmAMybua/bjDsSu8RQHbmw==", + "requires": { + "@smithy/fetch-http-handler": "^3.2.4", + "@smithy/node-http-handler": "^3.1.4", + "@smithy/types": "^3.3.0", + "@smithy/util-base64": "^3.0.0", + "@smithy/util-buffer-from": "^3.0.0", + "@smithy/util-hex-encoding": "^3.0.0", + "@smithy/util-utf8": "^3.0.0", + "tslib": "^2.6.2" + } + }, + "@smithy/util-uri-escape": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-uri-escape/-/util-uri-escape-3.0.0.tgz", + "integrity": "sha512-LqR7qYLgZTD7nWLBecUi4aqolw8Mhza9ArpNEQ881MJJIU2sE5iHCK6TdyqqzcDLy0OPe10IY4T8ctVdtynubg==", + "requires": { + "tslib": "^2.6.2" + } + }, + "@smithy/util-utf8": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-3.0.0.tgz", + "integrity": "sha512-rUeT12bxFnplYDe815GXbq/oixEGHfRFFtcTF3YdDi/JaENIM6aSYYLJydG83UNzLXeRI5K8abYd/8Sp/QM0kA==", + "requires": { + "@smithy/util-buffer-from": "^3.0.0", + "tslib": "^2.6.2" + } + }, + "fast-xml-parser": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.4.1.tgz", + "integrity": "sha512-xkjOecfnKGkSsOwtZ5Pz7Us/T6mrbPQrq0nh+aCO5V9nk5NLWmasAHumTKjiPJPWANe+kAZ84Jc8ooJkzZ88Sw==", + "requires": { + "strnum": "^1.0.5" + } } } }, - "@aws-crypto/sha256-browser": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-browser/-/sha256-browser-3.0.0.tgz", - "integrity": "sha512-8VLmW2B+gjFbU5uMeqtQM6Nj0/F1bro80xQXCW6CQBWgosFWXTx77aeOF5CAIAmbOK64SdMBJdNr6J41yP5mvQ==", - "optional": true, - "requires": { - "@aws-crypto/ie11-detection": "^3.0.0", - "@aws-crypto/sha256-js": "^3.0.0", - "@aws-crypto/supports-web-crypto": "^3.0.0", - "@aws-crypto/util": "^3.0.0", - "@aws-sdk/types": "^3.222.0", - "@aws-sdk/util-locate-window": "^3.0.0", - "@aws-sdk/util-utf8-browser": "^3.0.0", - "tslib": "^1.11.1" + "@aws-sdk/credential-provider-http": { + "version": "3.621.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.621.0.tgz", + "integrity": "sha512-/jc2tEsdkT1QQAI5Dvoci50DbSxtJrevemwFsm0B73pwCcOQZ5ZwwSdVqGsPutzYzUVx3bcXg3LRL7jLACqRIg==", + "requires": { + "@aws-sdk/types": "3.609.0", + "@smithy/fetch-http-handler": "^3.2.4", + "@smithy/node-http-handler": "^3.1.4", + "@smithy/property-provider": "^3.1.3", + "@smithy/protocol-http": "^4.1.0", + "@smithy/smithy-client": "^3.1.11", + "@smithy/types": "^3.3.0", + "@smithy/util-stream": "^3.1.3", + "tslib": "^2.6.2" }, "dependencies": { - "tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "optional": true - } - } - }, - "@aws-crypto/sha256-js": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-js/-/sha256-js-3.0.0.tgz", - "integrity": "sha512-PnNN7os0+yd1XvXAy23CFOmTbMaDxgxXtTKHybrJ39Y8kGzBATgBFibWJKH6BhytLI/Zyszs87xCOBNyBig6vQ==", - "optional": true, - "requires": { - "@aws-crypto/util": "^3.0.0", - "@aws-sdk/types": "^3.222.0", - "tslib": "^1.11.1" - }, - "dependencies": { - "tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "optional": true - } - } - }, - "@aws-crypto/supports-web-crypto": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@aws-crypto/supports-web-crypto/-/supports-web-crypto-3.0.0.tgz", - "integrity": "sha512-06hBdMwUAb2WFTuGG73LSC0wfPu93xWwo5vL2et9eymgmu3Id5vFAHBbajVWiGhPO37qcsdCap/FqXvJGJWPIg==", - "optional": true, - "requires": { - "tslib": "^1.11.1" - }, - "dependencies": { - "tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "optional": true - } - } - }, - "@aws-crypto/util": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@aws-crypto/util/-/util-3.0.0.tgz", - "integrity": "sha512-2OJlpeJpCR48CC8r+uKVChzs9Iungj9wkZrl8Z041DWEWvyIHILYKCPNzJghKsivj+S3mLo6BVc7mBNzdxA46w==", - "optional": true, - "requires": { - "@aws-sdk/types": "^3.222.0", - "@aws-sdk/util-utf8-browser": "^3.0.0", - "tslib": "^1.11.1" - }, - "dependencies": { - "tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "optional": true + "@aws-sdk/types": { + "version": "3.609.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.609.0.tgz", + "integrity": "sha512-+Tqnh9w0h2LcrUsdXyT1F8mNhXz+tVYBtP19LpeEGntmvHwa2XzvLUCWpoIAIVsHp5+HdB2X9Sn0KAtmbFXc2Q==", + "requires": { + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + } + }, + "@smithy/abort-controller": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@smithy/abort-controller/-/abort-controller-3.1.1.tgz", + "integrity": "sha512-MBJBiidoe+0cTFhyxT8g+9g7CeVccLM0IOKKUMCNQ1CNMJ/eIfoo0RTfVrXOONEI1UCN1W+zkiHSbzUNE9dZtQ==", + "requires": { + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + } + }, + "@smithy/fetch-http-handler": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-3.2.4.tgz", + "integrity": "sha512-kBprh5Gs5h7ug4nBWZi1FZthdqSM+T7zMmsZxx0IBvWUn7dK3diz2SHn7Bs4dQGFDk8plDv375gzenDoNwrXjg==", + "requires": { + "@smithy/protocol-http": "^4.1.0", + "@smithy/querystring-builder": "^3.0.3", + "@smithy/types": "^3.3.0", + "@smithy/util-base64": "^3.0.0", + "tslib": "^2.6.2" + } + }, + "@smithy/is-array-buffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-3.0.0.tgz", + "integrity": "sha512-+Fsu6Q6C4RSJiy81Y8eApjEB5gVtM+oFKTffg+jSuwtvomJJrhUJBu2zS8wjXSgH/g1MKEWrzyChTBe6clb5FQ==", + "requires": { + "tslib": "^2.6.2" + } + }, + "@smithy/middleware-endpoint": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@smithy/middleware-endpoint/-/middleware-endpoint-3.1.0.tgz", + "integrity": "sha512-5y5aiKCEwg9TDPB4yFE7H6tYvGFf1OJHNczeY10/EFF8Ir8jZbNntQJxMWNfeQjC1mxPsaQ6mR9cvQbf+0YeMw==", + "requires": { + "@smithy/middleware-serde": "^3.0.3", + "@smithy/node-config-provider": "^3.1.4", + "@smithy/shared-ini-file-loader": "^3.1.4", + "@smithy/types": "^3.3.0", + "@smithy/url-parser": "^3.0.3", + "@smithy/util-middleware": "^3.0.3", + "tslib": "^2.6.2" + } + }, + "@smithy/middleware-serde": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@smithy/middleware-serde/-/middleware-serde-3.0.3.tgz", + "integrity": "sha512-puUbyJQBcg9eSErFXjKNiGILJGtiqmuuNKEYNYfUD57fUl4i9+mfmThtQhvFXU0hCVG0iEJhvQUipUf+/SsFdA==", + "requires": { + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + } + }, + "@smithy/middleware-stack": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@smithy/middleware-stack/-/middleware-stack-3.0.3.tgz", + "integrity": "sha512-r4klY9nFudB0r9UdSMaGSyjyQK5adUyPnQN/ZM6M75phTxOdnc/AhpvGD1fQUvgmqjQEBGCwpnPbDm8pH5PapA==", + "requires": { + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + } + }, + "@smithy/node-config-provider": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/@smithy/node-config-provider/-/node-config-provider-3.1.4.tgz", + "integrity": "sha512-YvnElQy8HR4vDcAjoy7Xkx9YT8xZP4cBXcbJSgm/kxmiQu08DwUwj8rkGnyoJTpfl/3xYHH+d8zE+eHqoDCSdQ==", + "requires": { + "@smithy/property-provider": "^3.1.3", + "@smithy/shared-ini-file-loader": "^3.1.4", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + } + }, + "@smithy/node-http-handler": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-3.1.4.tgz", + "integrity": "sha512-+UmxgixgOr/yLsUxcEKGH0fMNVteJFGkmRltYFHnBMlogyFdpzn2CwqWmxOrfJELhV34v0WSlaqG1UtE1uXlJg==", + "requires": { + "@smithy/abort-controller": "^3.1.1", + "@smithy/protocol-http": "^4.1.0", + "@smithy/querystring-builder": "^3.0.3", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + } + }, + "@smithy/property-provider": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/@smithy/property-provider/-/property-provider-3.1.3.tgz", + "integrity": "sha512-zahyOVR9Q4PEoguJ/NrFP4O7SMAfYO1HLhB18M+q+Z4KFd4V2obiMnlVoUFzFLSPeVt1POyNWneHHrZaTMoc/g==", + "requires": { + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + } + }, + "@smithy/protocol-http": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-4.1.0.tgz", + "integrity": "sha512-dPVoHYQ2wcHooGXg3LQisa1hH0e4y0pAddPMeeUPipI1tEOqL6A4N0/G7abeq+K8wrwSgjk4C0wnD1XZpJm5aA==", + "requires": { + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + } + }, + "@smithy/querystring-builder": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@smithy/querystring-builder/-/querystring-builder-3.0.3.tgz", + "integrity": "sha512-vyWckeUeesFKzCDaRwWLUA1Xym9McaA6XpFfAK5qI9DKJ4M33ooQGqvM4J+LalH4u/Dq9nFiC8U6Qn1qi0+9zw==", + "requires": { + "@smithy/types": "^3.3.0", + "@smithy/util-uri-escape": "^3.0.0", + "tslib": "^2.6.2" + } + }, + "@smithy/querystring-parser": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@smithy/querystring-parser/-/querystring-parser-3.0.3.tgz", + "integrity": "sha512-zahM1lQv2YjmznnfQsWbYojFe55l0SLG/988brlLv1i8z3dubloLF+75ATRsqPBboUXsW6I9CPGE5rQgLfY0vQ==", + "requires": { + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + } + }, + "@smithy/shared-ini-file-loader": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/@smithy/shared-ini-file-loader/-/shared-ini-file-loader-3.1.4.tgz", + "integrity": "sha512-qMxS4hBGB8FY2GQqshcRUy1K6k8aBWP5vwm8qKkCT3A9K2dawUwOIJfqh9Yste/Bl0J2lzosVyrXDj68kLcHXQ==", + "requires": { + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + } + }, + "@smithy/smithy-client": { + "version": "3.1.11", + "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-3.1.11.tgz", + "integrity": "sha512-l0BpyYkciNyMaS+PnFFz4aO5sBcXvGLoJd7mX9xrMBIm2nIQBVvYgp2ZpPDMzwjKCavsXu06iuCm0F6ZJZc6yQ==", + "requires": { + "@smithy/middleware-endpoint": "^3.1.0", + "@smithy/middleware-stack": "^3.0.3", + "@smithy/protocol-http": "^4.1.0", + "@smithy/types": "^3.3.0", + "@smithy/util-stream": "^3.1.3", + "tslib": "^2.6.2" + } + }, + "@smithy/types": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-3.3.0.tgz", + "integrity": "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA==", + "requires": { + "tslib": "^2.6.2" + } + }, + "@smithy/url-parser": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@smithy/url-parser/-/url-parser-3.0.3.tgz", + "integrity": "sha512-pw3VtZtX2rg+s6HMs6/+u9+hu6oY6U7IohGhVNnjbgKy86wcIsSZwgHrFR+t67Uyxvp4Xz3p3kGXXIpTNisq8A==", + "requires": { + "@smithy/querystring-parser": "^3.0.3", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + } + }, + "@smithy/util-base64": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-base64/-/util-base64-3.0.0.tgz", + "integrity": "sha512-Kxvoh5Qtt0CDsfajiZOCpJxgtPHXOKwmM+Zy4waD43UoEMA+qPxxa98aE/7ZhdnBFZFXMOiBR5xbcaMhLtznQQ==", + "requires": { + "@smithy/util-buffer-from": "^3.0.0", + "@smithy/util-utf8": "^3.0.0", + "tslib": "^2.6.2" + } + }, + "@smithy/util-buffer-from": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-3.0.0.tgz", + "integrity": "sha512-aEOHCgq5RWFbP+UDPvPot26EJHjOC+bRgse5A8V3FSShqd5E5UN4qc7zkwsvJPPAVsf73QwYcHN1/gt/rtLwQA==", + "requires": { + "@smithy/is-array-buffer": "^3.0.0", + "tslib": "^2.6.2" + } + }, + "@smithy/util-hex-encoding": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-hex-encoding/-/util-hex-encoding-3.0.0.tgz", + "integrity": "sha512-eFndh1WEK5YMUYvy3lPlVmYY/fZcQE1D8oSf41Id2vCeIkKJXPcYDCZD+4+xViI6b1XSd7tE+s5AmXzz5ilabQ==", + "requires": { + "tslib": "^2.6.2" + } + }, + "@smithy/util-middleware": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@smithy/util-middleware/-/util-middleware-3.0.3.tgz", + "integrity": "sha512-l+StyYYK/eO3DlVPbU+4Bi06Jjal+PFLSMmlWM1BEwyLxZ3aKkf1ROnoIakfaA7mC6uw3ny7JBkau4Yc+5zfWw==", + "requires": { + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + } + }, + "@smithy/util-stream": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/@smithy/util-stream/-/util-stream-3.1.3.tgz", + "integrity": "sha512-FIv/bRhIlAxC0U7xM1BCnF2aDRPq0UaelqBHkM2lsCp26mcBbgI0tCVTv+jGdsQLUmAMybua/bjDsSu8RQHbmw==", + "requires": { + "@smithy/fetch-http-handler": "^3.2.4", + "@smithy/node-http-handler": "^3.1.4", + "@smithy/types": "^3.3.0", + "@smithy/util-base64": "^3.0.0", + "@smithy/util-buffer-from": "^3.0.0", + "@smithy/util-hex-encoding": "^3.0.0", + "@smithy/util-utf8": "^3.0.0", + "tslib": "^2.6.2" + } + }, + "@smithy/util-uri-escape": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-uri-escape/-/util-uri-escape-3.0.0.tgz", + "integrity": "sha512-LqR7qYLgZTD7nWLBecUi4aqolw8Mhza9ArpNEQ881MJJIU2sE5iHCK6TdyqqzcDLy0OPe10IY4T8ctVdtynubg==", + "requires": { + "tslib": "^2.6.2" + } + }, + "@smithy/util-utf8": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-3.0.0.tgz", + "integrity": "sha512-rUeT12bxFnplYDe815GXbq/oixEGHfRFFtcTF3YdDi/JaENIM6aSYYLJydG83UNzLXeRI5K8abYd/8Sp/QM0kA==", + "requires": { + "@smithy/util-buffer-from": "^3.0.0", + "tslib": "^2.6.2" + } } } }, - "@aws-sdk/client-cognito-identity": { - "version": "3.398.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-cognito-identity/-/client-cognito-identity-3.398.0.tgz", - "integrity": "sha512-Pr/S1f8R2FsJ8DwBC6g0CSdtZNNV5dMHhlIi+t8YAmCJvP4KT+UhzFjbvQRINlBRLFuGUuP7p5vRcGVELD3+wA==", - "optional": true, - "requires": { - "@aws-crypto/sha256-browser": "3.0.0", - "@aws-crypto/sha256-js": "3.0.0", - "@aws-sdk/client-sts": "3.398.0", - "@aws-sdk/credential-provider-node": "3.398.0", - "@aws-sdk/middleware-host-header": "3.398.0", - "@aws-sdk/middleware-logger": "3.398.0", - "@aws-sdk/middleware-recursion-detection": "3.398.0", - "@aws-sdk/middleware-signing": "3.398.0", - "@aws-sdk/middleware-user-agent": "3.398.0", - "@aws-sdk/types": "3.398.0", - "@aws-sdk/util-endpoints": "3.398.0", - "@aws-sdk/util-user-agent-browser": "3.398.0", - "@aws-sdk/util-user-agent-node": "3.398.0", - "@smithy/config-resolver": "^2.0.5", - "@smithy/fetch-http-handler": "^2.0.5", - "@smithy/hash-node": "^2.0.5", - "@smithy/invalid-dependency": "^2.0.5", - "@smithy/middleware-content-length": "^2.0.5", - "@smithy/middleware-endpoint": "^2.0.5", - "@smithy/middleware-retry": "^2.0.5", - "@smithy/middleware-serde": "^2.0.5", - "@smithy/middleware-stack": "^2.0.0", - "@smithy/node-config-provider": "^2.0.5", - "@smithy/node-http-handler": "^2.0.5", - "@smithy/protocol-http": "^2.0.5", - "@smithy/smithy-client": "^2.0.5", - "@smithy/types": "^2.2.2", - "@smithy/url-parser": "^2.0.5", - "@smithy/util-base64": "^2.0.0", - "@smithy/util-body-length-browser": "^2.0.0", - "@smithy/util-body-length-node": "^2.1.0", - "@smithy/util-defaults-mode-browser": "^2.0.5", - "@smithy/util-defaults-mode-node": "^2.0.5", - "@smithy/util-retry": "^2.0.0", - "@smithy/util-utf8": "^2.0.0", - "tslib": "^2.5.0" - } - }, - "@aws-sdk/client-sso": { - "version": "3.398.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.398.0.tgz", - "integrity": "sha512-CygL0jhfibw4kmWXG/3sfZMFNjcXo66XUuPC4BqZBk8Rj5vFoxp1vZeMkDLzTIk97Nvo5J5Bh+QnXKhub6AckQ==", - "optional": true, - "requires": { - "@aws-crypto/sha256-browser": "3.0.0", - "@aws-crypto/sha256-js": "3.0.0", - "@aws-sdk/middleware-host-header": "3.398.0", - "@aws-sdk/middleware-logger": "3.398.0", - "@aws-sdk/middleware-recursion-detection": "3.398.0", - "@aws-sdk/middleware-user-agent": "3.398.0", - "@aws-sdk/types": "3.398.0", - "@aws-sdk/util-endpoints": "3.398.0", - "@aws-sdk/util-user-agent-browser": "3.398.0", - "@aws-sdk/util-user-agent-node": "3.398.0", - "@smithy/config-resolver": "^2.0.5", - "@smithy/fetch-http-handler": "^2.0.5", - "@smithy/hash-node": "^2.0.5", - "@smithy/invalid-dependency": "^2.0.5", - "@smithy/middleware-content-length": "^2.0.5", - "@smithy/middleware-endpoint": "^2.0.5", - "@smithy/middleware-retry": "^2.0.5", - "@smithy/middleware-serde": "^2.0.5", - "@smithy/middleware-stack": "^2.0.0", - "@smithy/node-config-provider": "^2.0.5", - "@smithy/node-http-handler": "^2.0.5", - "@smithy/protocol-http": "^2.0.5", - "@smithy/smithy-client": "^2.0.5", - "@smithy/types": "^2.2.2", - "@smithy/url-parser": "^2.0.5", - "@smithy/util-base64": "^2.0.0", - "@smithy/util-body-length-browser": "^2.0.0", - "@smithy/util-body-length-node": "^2.1.0", - "@smithy/util-defaults-mode-browser": "^2.0.5", - "@smithy/util-defaults-mode-node": "^2.0.5", - "@smithy/util-retry": "^2.0.0", - "@smithy/util-utf8": "^2.0.0", - "tslib": "^2.5.0" - } - }, - "@aws-sdk/client-sts": { - "version": "3.398.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sts/-/client-sts-3.398.0.tgz", - "integrity": "sha512-/3Pa9wLMvBZipKraq3AtbmTfXW6q9kyvhwOno64f1Fz7kFb8ijQFMGoATS70B2pGEZTlxkUqJFWDiisT6Q6dFg==", - "optional": true, - "requires": { - "@aws-crypto/sha256-browser": "3.0.0", - "@aws-crypto/sha256-js": "3.0.0", - "@aws-sdk/credential-provider-node": "3.398.0", - "@aws-sdk/middleware-host-header": "3.398.0", - "@aws-sdk/middleware-logger": "3.398.0", - "@aws-sdk/middleware-recursion-detection": "3.398.0", - "@aws-sdk/middleware-sdk-sts": "3.398.0", - "@aws-sdk/middleware-signing": "3.398.0", - "@aws-sdk/middleware-user-agent": "3.398.0", - "@aws-sdk/types": "3.398.0", - "@aws-sdk/util-endpoints": "3.398.0", - "@aws-sdk/util-user-agent-browser": "3.398.0", - "@aws-sdk/util-user-agent-node": "3.398.0", - "@smithy/config-resolver": "^2.0.5", - "@smithy/fetch-http-handler": "^2.0.5", - "@smithy/hash-node": "^2.0.5", - "@smithy/invalid-dependency": "^2.0.5", - "@smithy/middleware-content-length": "^2.0.5", - "@smithy/middleware-endpoint": "^2.0.5", - "@smithy/middleware-retry": "^2.0.5", - "@smithy/middleware-serde": "^2.0.5", - "@smithy/middleware-stack": "^2.0.0", - "@smithy/node-config-provider": "^2.0.5", - "@smithy/node-http-handler": "^2.0.5", - "@smithy/protocol-http": "^2.0.5", - "@smithy/smithy-client": "^2.0.5", - "@smithy/types": "^2.2.2", - "@smithy/url-parser": "^2.0.5", - "@smithy/util-base64": "^2.0.0", - "@smithy/util-body-length-browser": "^2.0.0", - "@smithy/util-body-length-node": "^2.1.0", - "@smithy/util-defaults-mode-browser": "^2.0.5", - "@smithy/util-defaults-mode-node": "^2.0.5", - "@smithy/util-retry": "^2.0.0", - "@smithy/util-utf8": "^2.0.0", - "fast-xml-parser": "4.2.5", - "tslib": "^2.5.0" - } - }, - "@aws-sdk/credential-provider-cognito-identity": { - "version": "3.398.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-cognito-identity/-/credential-provider-cognito-identity-3.398.0.tgz", - "integrity": "sha512-MFUhy1YayHg5ypRTk4OTfDumQRP+OJBagaGv14kA8DzhKH1sNrU4HV7A7y2J4SvkN5hG/KnLJqxpakCtB2/O2g==", - "optional": true, - "requires": { - "@aws-sdk/client-cognito-identity": "3.398.0", - "@aws-sdk/types": "3.398.0", - "@smithy/property-provider": "^2.0.0", - "@smithy/types": "^2.2.2", - "tslib": "^2.5.0" - } - }, - "@aws-sdk/credential-provider-env": { - "version": "3.398.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.398.0.tgz", - "integrity": "sha512-Z8Yj5z7FroAsR6UVML+XUdlpoqEe9Dnle8c2h8/xWwIC2feTfIBhjLhRVxfbpbM1pLgBSNEcZ7U8fwq5l7ESVQ==", - "optional": true, - "requires": { - "@aws-sdk/types": "3.398.0", - "@smithy/property-provider": "^2.0.0", - "@smithy/types": "^2.2.2", - "tslib": "^2.5.0" - } - }, - "@aws-sdk/credential-provider-ini": { - "version": "3.398.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.398.0.tgz", - "integrity": "sha512-AsK1lStK3nB9Cn6S6ODb1ktGh7SRejsNVQVKX3t5d3tgOaX+aX1Iwy8FzM/ZEN8uCloeRifUGIY9uQFygg5mSw==", - "optional": true, - "requires": { - "@aws-sdk/credential-provider-env": "3.398.0", - "@aws-sdk/credential-provider-process": "3.398.0", - "@aws-sdk/credential-provider-sso": "3.398.0", - "@aws-sdk/credential-provider-web-identity": "3.398.0", - "@aws-sdk/types": "3.398.0", - "@smithy/credential-provider-imds": "^2.0.0", - "@smithy/property-provider": "^2.0.0", - "@smithy/shared-ini-file-loader": "^2.0.0", - "@smithy/types": "^2.2.2", - "tslib": "^2.5.0" - } - }, - "@aws-sdk/credential-provider-node": { - "version": "3.398.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.398.0.tgz", - "integrity": "sha512-odmI/DSKfuWUYeDnGTCEHBbC8/MwnF6yEq874zl6+owoVv0ZsYP8qBHfiJkYqrwg7wQ7Pi40sSAPC1rhesGwzg==", - "optional": true, - "requires": { - "@aws-sdk/credential-provider-env": "3.398.0", - "@aws-sdk/credential-provider-ini": "3.398.0", - "@aws-sdk/credential-provider-process": "3.398.0", - "@aws-sdk/credential-provider-sso": "3.398.0", - "@aws-sdk/credential-provider-web-identity": "3.398.0", - "@aws-sdk/types": "3.398.0", - "@smithy/credential-provider-imds": "^2.0.0", - "@smithy/property-provider": "^2.0.0", - "@smithy/shared-ini-file-loader": "^2.0.0", - "@smithy/types": "^2.2.2", - "tslib": "^2.5.0" - } - }, - "@aws-sdk/credential-provider-process": { - "version": "3.398.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.398.0.tgz", - "integrity": "sha512-WrkBL1W7TXN508PA9wRXPFtzmGpVSW98gDaHEaa8GolAPHMPa5t2QcC/z/cFpglzrcVv8SA277zu9Z8tELdZhg==", - "optional": true, - "requires": { - "@aws-sdk/types": "3.398.0", - "@smithy/property-provider": "^2.0.0", - "@smithy/shared-ini-file-loader": "^2.0.0", - "@smithy/types": "^2.2.2", - "tslib": "^2.5.0" - } - }, - "@aws-sdk/credential-provider-sso": { - "version": "3.398.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.398.0.tgz", - "integrity": "sha512-2Dl35587xbnzR/GGZqA2MnFs8+kS4wbHQO9BioU0okA+8NRueohNMdrdQmQDdSNK4BfIpFspiZmFkXFNyEAfgw==", - "optional": true, - "requires": { - "@aws-sdk/client-sso": "3.398.0", - "@aws-sdk/token-providers": "3.398.0", - "@aws-sdk/types": "3.398.0", - "@smithy/property-provider": "^2.0.0", - "@smithy/shared-ini-file-loader": "^2.0.0", - "@smithy/types": "^2.2.2", - "tslib": "^2.5.0" - } - }, - "@aws-sdk/credential-provider-web-identity": { - "version": "3.398.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.398.0.tgz", - "integrity": "sha512-iG3905Alv9pINbQ8/MIsshgqYMbWx+NDQWpxbIW3W0MkSH3iAqdVpSCteYidYX9G/jv2Um1nW3y360ib20bvNg==", - "optional": true, - "requires": { - "@aws-sdk/types": "3.398.0", - "@smithy/property-provider": "^2.0.0", - "@smithy/types": "^2.2.2", - "tslib": "^2.5.0" - } - }, "@aws-sdk/credential-providers": { - "version": "3.398.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-providers/-/credential-providers-3.398.0.tgz", - "integrity": "sha512-355vXmImn2e85mIWSYDVb101AF2lIVHKNCaH6sV1U/8i0ZOXh2cJYNdkRYrxNt1ezDB0k97lSKvuDx7RDvJyRg==", - "optional": true, - "requires": { - "@aws-sdk/client-cognito-identity": "3.398.0", - "@aws-sdk/client-sso": "3.398.0", - "@aws-sdk/client-sts": "3.398.0", - "@aws-sdk/credential-provider-cognito-identity": "3.398.0", - "@aws-sdk/credential-provider-env": "3.398.0", - "@aws-sdk/credential-provider-ini": "3.398.0", - "@aws-sdk/credential-provider-node": "3.398.0", - "@aws-sdk/credential-provider-process": "3.398.0", - "@aws-sdk/credential-provider-sso": "3.398.0", - "@aws-sdk/credential-provider-web-identity": "3.398.0", - "@aws-sdk/types": "3.398.0", - "@smithy/credential-provider-imds": "^2.0.0", - "@smithy/property-provider": "^2.0.0", - "@smithy/types": "^2.2.2", - "tslib": "^2.5.0" - } - }, - "@aws-sdk/middleware-host-header": { - "version": "3.398.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.398.0.tgz", - "integrity": "sha512-m+5laWdBaxIZK2ko0OwcCHJZJ5V1MgEIt8QVQ3k4/kOkN9ICjevOYmba751pHoTnbOYB7zQd6D2OT3EYEEsUcA==", - "optional": true, - "requires": { - "@aws-sdk/types": "3.398.0", - "@smithy/protocol-http": "^2.0.5", - "@smithy/types": "^2.2.2", - "tslib": "^2.5.0" - } - }, - "@aws-sdk/middleware-logger": { - "version": "3.398.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.398.0.tgz", - "integrity": "sha512-CiJjW+FL12elS6Pn7/UVjVK8HWHhXMfvHZvOwx/Qkpy340sIhkuzOO6fZEruECDTZhl2Wqn81XdJ1ZQ4pRKpCg==", - "optional": true, - "requires": { - "@aws-sdk/types": "3.398.0", - "@smithy/types": "^2.2.2", - "tslib": "^2.5.0" - } - }, - "@aws-sdk/middleware-recursion-detection": { - "version": "3.398.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.398.0.tgz", - "integrity": "sha512-7QpOqPQAZNXDXv6vsRex4R8dLniL0E/80OPK4PPFsrCh9btEyhN9Begh4i1T+5lL28hmYkztLOkTQ2N5J3hgRQ==", - "optional": true, - "requires": { - "@aws-sdk/types": "3.398.0", - "@smithy/protocol-http": "^2.0.5", - "@smithy/types": "^2.2.2", - "tslib": "^2.5.0" - } - }, - "@aws-sdk/middleware-sdk-sts": { - "version": "3.398.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-sdk-sts/-/middleware-sdk-sts-3.398.0.tgz", - "integrity": "sha512-+JH76XHEgfVihkY+GurohOQ5Z83zVN1nYcQzwCFnCDTh4dG4KwhnZKG+WPw6XJECocY0R+H0ivofeALHvVWJtQ==", - "optional": true, - "requires": { - "@aws-sdk/middleware-signing": "3.398.0", - "@aws-sdk/types": "3.398.0", - "@smithy/types": "^2.2.2", - "tslib": "^2.5.0" - } - }, - "@aws-sdk/middleware-signing": { - "version": "3.398.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-signing/-/middleware-signing-3.398.0.tgz", - "integrity": "sha512-O0KqXAix1TcvZBFt1qoFkHMUNJOSgjJTYS7lFTRKSwgsD27bdW2TM2r9R8DAccWFt5Amjkdt+eOwQMIXPGTm8w==", - "optional": true, - "requires": { - "@aws-sdk/types": "3.398.0", - "@smithy/property-provider": "^2.0.0", - "@smithy/protocol-http": "^2.0.5", - "@smithy/signature-v4": "^2.0.0", - "@smithy/types": "^2.2.2", - "@smithy/util-middleware": "^2.0.0", - "tslib": "^2.5.0" - } - }, - "@aws-sdk/middleware-user-agent": { - "version": "3.398.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.398.0.tgz", - "integrity": "sha512-nF1jg0L+18b5HvTcYzwyFgfZQQMELJINFqI0mi4yRKaX7T5a3aGp5RVLGGju/6tAGTuFbfBoEhkhU3kkxexPYQ==", - "optional": true, - "requires": { - "@aws-sdk/types": "3.398.0", - "@aws-sdk/util-endpoints": "3.398.0", - "@smithy/protocol-http": "^2.0.5", - "@smithy/types": "^2.2.2", - "tslib": "^2.5.0" - } - }, - "@aws-sdk/token-providers": { - "version": "3.398.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.398.0.tgz", - "integrity": "sha512-nrYgjzavGCKJL/48Vt0EL+OlIc5UZLfNGpgyUW9cv3XZwl+kXV0QB+HH0rHZZLfpbBgZ2RBIJR9uD5ieu/6hpQ==", - "optional": true, - "requires": { - "@aws-crypto/sha256-browser": "3.0.0", - "@aws-crypto/sha256-js": "3.0.0", - "@aws-sdk/middleware-host-header": "3.398.0", - "@aws-sdk/middleware-logger": "3.398.0", - "@aws-sdk/middleware-recursion-detection": "3.398.0", - "@aws-sdk/middleware-user-agent": "3.398.0", - "@aws-sdk/types": "3.398.0", - "@aws-sdk/util-endpoints": "3.398.0", - "@aws-sdk/util-user-agent-browser": "3.398.0", - "@aws-sdk/util-user-agent-node": "3.398.0", - "@smithy/config-resolver": "^2.0.5", - "@smithy/fetch-http-handler": "^2.0.5", - "@smithy/hash-node": "^2.0.5", - "@smithy/invalid-dependency": "^2.0.5", - "@smithy/middleware-content-length": "^2.0.5", - "@smithy/middleware-endpoint": "^2.0.5", - "@smithy/middleware-retry": "^2.0.5", - "@smithy/middleware-serde": "^2.0.5", - "@smithy/middleware-stack": "^2.0.0", - "@smithy/node-config-provider": "^2.0.5", - "@smithy/node-http-handler": "^2.0.5", - "@smithy/property-provider": "^2.0.0", - "@smithy/protocol-http": "^2.0.5", - "@smithy/shared-ini-file-loader": "^2.0.0", - "@smithy/smithy-client": "^2.0.5", - "@smithy/types": "^2.2.2", - "@smithy/url-parser": "^2.0.5", - "@smithy/util-base64": "^2.0.0", - "@smithy/util-body-length-browser": "^2.0.0", - "@smithy/util-body-length-node": "^2.1.0", - "@smithy/util-defaults-mode-browser": "^2.0.5", - "@smithy/util-defaults-mode-node": "^2.0.5", - "@smithy/util-retry": "^2.0.0", - "@smithy/util-utf8": "^2.0.0", - "tslib": "^2.5.0" - } - }, - "@aws-sdk/types": { - "version": "3.398.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.398.0.tgz", - "integrity": "sha512-r44fkS+vsEgKCuEuTV+TIk0t0m5ZlXHNjSDYEUvzLStbbfUFiNus/YG4UCa0wOk9R7VuQI67badsvvPeVPCGDQ==", - "optional": true, - "requires": { - "@smithy/types": "^2.2.2", - "tslib": "^2.5.0" - } - }, - "@aws-sdk/util-endpoints": { - "version": "3.398.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.398.0.tgz", - "integrity": "sha512-Fy0gLYAei/Rd6BrXG4baspCnWTUSd0NdokU1pZh4KlfEAEN1i8SPPgfiO5hLk7+2inqtCmqxVJlfqbMVe9k4bw==", - "optional": true, - "requires": { - "@aws-sdk/types": "3.398.0", - "tslib": "^2.5.0" - } - }, - "@aws-sdk/util-locate-window": { - "version": "3.310.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-locate-window/-/util-locate-window-3.310.0.tgz", - "integrity": "sha512-qo2t/vBTnoXpjKxlsC2e1gBrRm80M3bId27r0BRB2VniSSe7bL1mmzM+/HFtujm0iAxtPM+aLEflLJlJeDPg0w==", - "optional": true, - "requires": { - "tslib": "^2.5.0" - } - }, - "@aws-sdk/util-user-agent-browser": { - "version": "3.398.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.398.0.tgz", - "integrity": "sha512-A3Tzx1tkDHlBT+IgxmsMCHbV8LM7SwwCozq2ZjJRx0nqw3MCrrcxQFXldHeX/gdUMO+0Oocb7HGSnVODTq+0EA==", - "optional": true, - "requires": { - "@aws-sdk/types": "3.398.0", - "@smithy/types": "^2.2.2", - "bowser": "^2.11.0", - "tslib": "^2.5.0" - } - }, - "@aws-sdk/util-user-agent-node": { - "version": "3.398.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.398.0.tgz", - "integrity": "sha512-RTVQofdj961ej4//fEkppFf4KXqKGMTCqJYghx3G0C/MYXbg7MGl7LjfNGtJcboRE8pfHHQ/TUWBDA7RIAPPlQ==", - "optional": true, - "requires": { - "@aws-sdk/types": "3.398.0", - "@smithy/node-config-provider": "^2.0.5", - "@smithy/types": "^2.2.2", - "tslib": "^2.5.0" - } - }, - "@aws-sdk/util-utf8-browser": { - "version": "3.259.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-utf8-browser/-/util-utf8-browser-3.259.0.tgz", - "integrity": "sha512-UvFa/vR+e19XookZF8RzFZBrw2EUkQWxiBW0yYQAhvk3C+QVGl0H3ouca8LDBlBfQKXwmW3huo/59H8rwb1wJw==", - "optional": true, - "requires": { - "tslib": "^2.3.1" - } - }, - "@mongodb-js/saslprep": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@mongodb-js/saslprep/-/saslprep-1.1.0.tgz", - "integrity": "sha512-Xfijy7HvfzzqiOAhAepF4SGN5e9leLkMvg/OPOF97XemjfVCYN/oWa75wnkc6mltMSTwY+XlbhWgUOJmkFspSw==", - "optional": true, - "requires": { - "sparse-bitfield": "^3.0.3" - } - }, - "@smithy/abort-controller": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@smithy/abort-controller/-/abort-controller-2.0.5.tgz", - "integrity": "sha512-byVZ2KWLMPYAZGKjRpniAzLcygJO4ruClZKdJTuB0eCB76ONFTdptBHlviHpAZXknRz7skYWPfcgO9v30A1SyA==", - "optional": true, - "requires": { - "@smithy/types": "^2.2.2", - "tslib": "^2.5.0" - } - }, - "@smithy/config-resolver": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@smithy/config-resolver/-/config-resolver-2.0.5.tgz", - "integrity": "sha512-n0c2AXz+kjALY2FQr7Zy9zhYigXzboIh1AuUUVCqFBKFtdEvTwnwPXrTDoEehLiRTUHNL+4yzZ3s+D0kKYSLSg==", - "optional": true, - "requires": { - "@smithy/types": "^2.2.2", - "@smithy/util-config-provider": "^2.0.0", - "@smithy/util-middleware": "^2.0.0", - "tslib": "^2.5.0" - } - }, - "@smithy/credential-provider-imds": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@smithy/credential-provider-imds/-/credential-provider-imds-2.0.5.tgz", - "integrity": "sha512-KFcf/e0meFkQNyteJ65f1G19sgUEY1e5zL7hyAEUPz2SEfBmC9B37WyRq87G3MEEsvmAWwCRu7nFFYUKtR3svQ==", - "optional": true, - "requires": { - "@smithy/node-config-provider": "^2.0.5", - "@smithy/property-provider": "^2.0.5", - "@smithy/types": "^2.2.2", - "@smithy/url-parser": "^2.0.5", - "tslib": "^2.5.0" - } - }, - "@smithy/eventstream-codec": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@smithy/eventstream-codec/-/eventstream-codec-2.0.5.tgz", - "integrity": "sha512-iqR6OuOV3zbQK8uVs9o+9AxhVk8kW9NAxA71nugwUB+kTY9C35pUd0A5/m4PRT0Y0oIW7W4kgnSR3fdYXQjECw==", - "optional": true, - "requires": { - "@aws-crypto/crc32": "3.0.0", - "@smithy/types": "^2.2.2", - "@smithy/util-hex-encoding": "^2.0.0", - "tslib": "^2.5.0" - } - }, - "@smithy/fetch-http-handler": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-2.0.5.tgz", - "integrity": "sha512-EzFoMowdBNy1VqtvkiXgPFEdosIAt4/4bgZ8uiDiUyfhmNXq/3bV+CagPFFBsgFOR/X2XK4zFZHRsoa7PNHVVg==", - "optional": true, - "requires": { - "@smithy/protocol-http": "^2.0.5", - "@smithy/querystring-builder": "^2.0.5", - "@smithy/types": "^2.2.2", - "@smithy/util-base64": "^2.0.0", - "tslib": "^2.5.0" - } - }, - "@smithy/hash-node": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@smithy/hash-node/-/hash-node-2.0.5.tgz", - "integrity": "sha512-mk551hIywBITT+kXruRNXk7f8Fy7DTzBjZJSr/V6nolYKmUHIG3w5QU6nO9qPYEQGKc/yEPtkpdS28ndeG93lA==", - "optional": true, - "requires": { - "@smithy/types": "^2.2.2", - "@smithy/util-buffer-from": "^2.0.0", - "@smithy/util-utf8": "^2.0.0", - "tslib": "^2.5.0" - } - }, - "@smithy/invalid-dependency": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@smithy/invalid-dependency/-/invalid-dependency-2.0.5.tgz", - "integrity": "sha512-0wEi+JT0hM+UUwrJVYbqjuGFhy5agY/zXyiN7BNAJ1XoCDjU5uaNSj8ekPWsXd/d4yM6NSe8UbPd8cOc1+3oBQ==", - "optional": true, - "requires": { - "@smithy/types": "^2.2.2", - "tslib": "^2.5.0" - } - }, - "@smithy/is-array-buffer": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-2.0.0.tgz", - "integrity": "sha512-z3PjFjMyZNI98JFRJi/U0nGoLWMSJlDjAW4QUX2WNZLas5C0CmVV6LJ01JI0k90l7FvpmixjWxPFmENSClQ7ug==", - "optional": true, - "requires": { - "tslib": "^2.5.0" - } - }, - "@smithy/middleware-content-length": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@smithy/middleware-content-length/-/middleware-content-length-2.0.5.tgz", - "integrity": "sha512-E7VwV5H02fgZIUGRli4GevBCAPvkyEI/fgl9SU47nPPi3DAAX3nEtUb8xfGbXjOcJ5BdSUoWWZn42tEd/blOqA==", - "optional": true, - "requires": { - "@smithy/protocol-http": "^2.0.5", - "@smithy/types": "^2.2.2", - "tslib": "^2.5.0" - } - }, - "@smithy/middleware-endpoint": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@smithy/middleware-endpoint/-/middleware-endpoint-2.0.5.tgz", - "integrity": "sha512-tyzDuoNTbsMQCq5Xkc4QOt6e2GACUllQIV8SQ5fc59FtOIV9/vbf58/GxVjZm2o8+MMbdDBANjTDZe/ijZKfyA==", - "optional": true, - "requires": { - "@smithy/middleware-serde": "^2.0.5", - "@smithy/types": "^2.2.2", - "@smithy/url-parser": "^2.0.5", - "@smithy/util-middleware": "^2.0.0", - "tslib": "^2.5.0" - } - }, - "@smithy/middleware-retry": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@smithy/middleware-retry/-/middleware-retry-2.0.5.tgz", - "integrity": "sha512-ulIfbFyzQTVnJbLjUl1CTSi0etg6tej/ekwaLp0Gn8ybUkDkKYa+uB6CF/m2J5B6meRwyJlsryR+DjaOVyiicg==", - "optional": true, - "requires": { - "@smithy/protocol-http": "^2.0.5", - "@smithy/service-error-classification": "^2.0.0", - "@smithy/types": "^2.2.2", - "@smithy/util-middleware": "^2.0.0", - "@smithy/util-retry": "^2.0.0", - "tslib": "^2.5.0", - "uuid": "^8.3.2" + "version": "3.621.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-providers/-/credential-providers-3.621.0.tgz", + "integrity": "sha512-FQbC7I8ae/72ZekLBa45jWJ+Q3d+YPhc3bW/rCks6RrldM6RgLTGr8pTOPCxHl828ky10RjkBiBmVU818rliyw==", + "requires": { + "@aws-sdk/client-cognito-identity": "3.621.0", + "@aws-sdk/client-sso": "3.621.0", + "@aws-sdk/client-sts": "3.621.0", + "@aws-sdk/credential-provider-cognito-identity": "3.621.0", + "@aws-sdk/credential-provider-env": "3.620.1", + "@aws-sdk/credential-provider-http": "3.621.0", + "@aws-sdk/credential-provider-ini": "3.621.0", + "@aws-sdk/credential-provider-node": "3.621.0", + "@aws-sdk/credential-provider-process": "3.620.1", + "@aws-sdk/credential-provider-sso": "3.621.0", + "@aws-sdk/credential-provider-web-identity": "3.621.0", + "@aws-sdk/types": "3.609.0", + "@smithy/credential-provider-imds": "^3.2.0", + "@smithy/property-provider": "^3.1.3", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" }, "dependencies": { - "uuid": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", - "optional": true - } - } - }, - "@smithy/middleware-serde": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@smithy/middleware-serde/-/middleware-serde-2.0.5.tgz", - "integrity": "sha512-in0AA5sous74dOfTGU9rMJBXJ0bDVNxwdXtEt5lh3FVd2sEyjhI+rqpLLRF1E4ixbw3RSEf80hfRpcPdjg4vvQ==", - "optional": true, - "requires": { - "@smithy/types": "^2.2.2", - "tslib": "^2.5.0" - } - }, - "@smithy/middleware-stack": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@smithy/middleware-stack/-/middleware-stack-2.0.0.tgz", - "integrity": "sha512-31XC1xNF65nlbc16yuh3wwTudmqs6qy4EseQUGF8A/p2m/5wdd/cnXJqpniy/XvXVwkHPz/GwV36HqzHtIKATQ==", - "optional": true, - "requires": { - "tslib": "^2.5.0" - } - }, - "@smithy/node-config-provider": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@smithy/node-config-provider/-/node-config-provider-2.0.5.tgz", - "integrity": "sha512-LRtjV9WkhONe2lVy+ipB/l1GX60ybzBmFyeRUoLUXWKdnZ3o81jsnbKzMK8hKq8eFSWPk+Lmyx6ZzCQabGeLxg==", - "optional": true, - "requires": { - "@smithy/property-provider": "^2.0.5", - "@smithy/shared-ini-file-loader": "^2.0.5", - "@smithy/types": "^2.2.2", - "tslib": "^2.5.0" - } - }, - "@smithy/node-http-handler": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-2.0.5.tgz", - "integrity": "sha512-lZm5DZf4b3V0saUw9WTC4/du887P6cy2fUyQgQQKRRV6OseButyD5yTzeMmXE53CaXJBMBsUvvIQ0hRVxIq56w==", - "optional": true, - "requires": { - "@smithy/abort-controller": "^2.0.5", - "@smithy/protocol-http": "^2.0.5", - "@smithy/querystring-builder": "^2.0.5", - "@smithy/types": "^2.2.2", - "tslib": "^2.5.0" - } - }, - "@smithy/property-provider": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@smithy/property-provider/-/property-provider-2.0.5.tgz", - "integrity": "sha512-cAFSUhX6aiHcmpWfrCLKvwBtgN1F6A0N8qY/8yeSi0LRLmhGqsY1/YTxFE185MCVzYbqBGXVr9TBv4RUcIV4rA==", - "optional": true, - "requires": { - "@smithy/types": "^2.2.2", - "tslib": "^2.5.0" - } - }, - "@smithy/protocol-http": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-2.0.5.tgz", - "integrity": "sha512-d2hhHj34mA2V86doiDfrsy2fNTnUOowGaf9hKb0hIPHqvcnShU4/OSc4Uf1FwHkAdYF3cFXTrj5VGUYbEuvMdw==", - "optional": true, - "requires": { - "@smithy/types": "^2.2.2", - "tslib": "^2.5.0" - } - }, - "@smithy/querystring-builder": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@smithy/querystring-builder/-/querystring-builder-2.0.5.tgz", - "integrity": "sha512-4DCX9krxLzATj+HdFPC3i8pb7XTAWzzKqSw8aTZMjXjtQY+vhe4azMAqIvbb6g7JKwIkmkRAjK6EXO3YWSnJVQ==", - "optional": true, - "requires": { - "@smithy/types": "^2.2.2", - "@smithy/util-uri-escape": "^2.0.0", - "tslib": "^2.5.0" - } - }, - "@smithy/querystring-parser": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@smithy/querystring-parser/-/querystring-parser-2.0.5.tgz", - "integrity": "sha512-C2stCULH0r54KBksv3AWcN8CLS3u9+WsEW8nBrvctrJ5rQTNa1waHkffpVaiKvcW2nP0aIMBPCobD/kYf/q9mA==", - "optional": true, - "requires": { - "@smithy/types": "^2.2.2", - "tslib": "^2.5.0" - } - }, - "@smithy/service-error-classification": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@smithy/service-error-classification/-/service-error-classification-2.0.0.tgz", - "integrity": "sha512-2z5Nafy1O0cTf69wKyNjGW/sNVMiqDnb4jgwfMG8ye8KnFJ5qmJpDccwIbJNhXIfbsxTg9SEec2oe1cexhMJvw==", - "optional": true - }, - "@smithy/shared-ini-file-loader": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@smithy/shared-ini-file-loader/-/shared-ini-file-loader-2.0.5.tgz", - "integrity": "sha512-Mvtk6FwMtfbKRC4YuSsIqRYp9WTxsSUJVVo2djgyhcacKGMqicHDWSAmgy3sDrKv+G/G6xTZCPwm6pJARtdxVg==", - "optional": true, - "requires": { - "@smithy/types": "^2.2.2", - "tslib": "^2.5.0" - } - }, - "@smithy/signature-v4": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@smithy/signature-v4/-/signature-v4-2.0.5.tgz", - "integrity": "sha512-ABIzXmUDXK4n2c9cXjQLELgH2RdtABpYKT+U131e2I6RbCypFZmxIHmIBufJzU2kdMCQ3+thBGDWorAITFW04A==", - "optional": true, - "requires": { - "@smithy/eventstream-codec": "^2.0.5", - "@smithy/is-array-buffer": "^2.0.0", - "@smithy/types": "^2.2.2", - "@smithy/util-hex-encoding": "^2.0.0", - "@smithy/util-middleware": "^2.0.0", - "@smithy/util-uri-escape": "^2.0.0", - "@smithy/util-utf8": "^2.0.0", - "tslib": "^2.5.0" - } - }, - "@smithy/smithy-client": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-2.0.5.tgz", - "integrity": "sha512-kCTFr8wfOAWKDzGvfBElc6shHigWtHNhMQ1IbosjC4jOlayFyZMSs2PysKB+Ox/dhQ41KqOzgVjgiQ+PyWqHMQ==", - "optional": true, - "requires": { - "@smithy/middleware-stack": "^2.0.0", - "@smithy/types": "^2.2.2", - "@smithy/util-stream": "^2.0.5", - "tslib": "^2.5.0" - } - }, - "@smithy/types": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-2.2.2.tgz", - "integrity": "sha512-4PS0y1VxDnELGHGgBWlDksB2LJK8TG8lcvlWxIsgR+8vROI7Ms8h1P4FQUx+ftAX2QZv5g1CJCdhdRmQKyonyw==", - "optional": true, - "requires": { - "tslib": "^2.5.0" - } - }, - "@smithy/url-parser": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@smithy/url-parser/-/url-parser-2.0.5.tgz", - "integrity": "sha512-OdMBvZhpckQSkugCXNJQCvqJ71wE7Ftxce92UOQLQ9pwF6hoS5PLL7wEfpnuEXtStzBqJYkzu1C1ZfjuFGOXAA==", - "optional": true, - "requires": { - "@smithy/querystring-parser": "^2.0.5", - "@smithy/types": "^2.2.2", - "tslib": "^2.5.0" - } - }, - "@smithy/util-base64": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@smithy/util-base64/-/util-base64-2.0.0.tgz", - "integrity": "sha512-Zb1E4xx+m5Lud8bbeYi5FkcMJMnn+1WUnJF3qD7rAdXpaL7UjkFQLdmW5fHadoKbdHpwH9vSR8EyTJFHJs++tA==", - "optional": true, - "requires": { - "@smithy/util-buffer-from": "^2.0.0", - "tslib": "^2.5.0" - } - }, - "@smithy/util-body-length-browser": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@smithy/util-body-length-browser/-/util-body-length-browser-2.0.0.tgz", - "integrity": "sha512-JdDuS4ircJt+FDnaQj88TzZY3+njZ6O+D3uakS32f2VNnDo3vyEuNdBOh/oFd8Df1zSZOuH1HEChk2AOYDezZg==", - "optional": true, - "requires": { - "tslib": "^2.5.0" - } - }, - "@smithy/util-body-length-node": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@smithy/util-body-length-node/-/util-body-length-node-2.1.0.tgz", - "integrity": "sha512-/li0/kj/y3fQ3vyzn36NTLGmUwAICb7Jbe/CsWCktW363gh1MOcpEcSO3mJ344Gv2dqz8YJCLQpb6hju/0qOWw==", - "optional": true, - "requires": { - "tslib": "^2.5.0" - } - }, - "@smithy/util-buffer-from": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-2.0.0.tgz", - "integrity": "sha512-/YNnLoHsR+4W4Vf2wL5lGv0ksg8Bmk3GEGxn2vEQt52AQaPSCuaO5PM5VM7lP1K9qHRKHwrPGktqVoAHKWHxzw==", - "optional": true, - "requires": { - "@smithy/is-array-buffer": "^2.0.0", - "tslib": "^2.5.0" - } - }, - "@smithy/util-config-provider": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@smithy/util-config-provider/-/util-config-provider-2.0.0.tgz", - "integrity": "sha512-xCQ6UapcIWKxXHEU4Mcs2s7LcFQRiU3XEluM2WcCjjBtQkUN71Tb+ydGmJFPxMUrW/GWMgQEEGipLym4XG0jZg==", - "optional": true, - "requires": { - "tslib": "^2.5.0" - } - }, - "@smithy/util-defaults-mode-browser": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-2.0.5.tgz", - "integrity": "sha512-yciP6TPttLsj731aHTvekgyuCGXQrEAJibEwEWAh3kzaDsfGAVCuZSBlyvC2Dl3TZmHKCOQwHV8mIE7KQCTPuQ==", - "optional": true, - "requires": { - "@smithy/property-provider": "^2.0.5", - "@smithy/types": "^2.2.2", - "bowser": "^2.11.0", - "tslib": "^2.5.0" + "@aws-crypto/sha256-browser": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-browser/-/sha256-browser-5.2.0.tgz", + "integrity": "sha512-AXfN/lGotSQwu6HNcEsIASo7kWXZ5HYWvfOmSNKDsEqC4OashTp8alTmaz+F7TC2L083SFv5RdB+qU3Vs1kZqw==", + "requires": { + "@aws-crypto/sha256-js": "^5.2.0", + "@aws-crypto/supports-web-crypto": "^5.2.0", + "@aws-crypto/util": "^5.2.0", + "@aws-sdk/types": "^3.222.0", + "@aws-sdk/util-locate-window": "^3.0.0", + "@smithy/util-utf8": "^2.0.0", + "tslib": "^2.6.2" + }, + "dependencies": { + "@smithy/util-utf8": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-2.3.0.tgz", + "integrity": "sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A==", + "requires": { + "@smithy/util-buffer-from": "^2.2.0", + "tslib": "^2.6.2" + } + } + } + }, + "@aws-crypto/sha256-js": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-js/-/sha256-js-5.2.0.tgz", + "integrity": "sha512-FFQQyu7edu4ufvIZ+OadFpHHOt+eSTBaYaki44c+akjg7qZg9oOQeLlk77F6tSYqjDAFClrHJk9tMf0HdVyOvA==", + "requires": { + "@aws-crypto/util": "^5.2.0", + "@aws-sdk/types": "^3.222.0", + "tslib": "^2.6.2" + } + }, + "@aws-crypto/supports-web-crypto": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/supports-web-crypto/-/supports-web-crypto-5.2.0.tgz", + "integrity": "sha512-iAvUotm021kM33eCdNfwIN//F77/IADDSs58i+MDaOqFrVjZo9bAal0NK7HurRuWLLpF1iLX7gbWrjHjeo+YFg==", + "requires": { + "tslib": "^2.6.2" + } + }, + "@aws-crypto/util": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/util/-/util-5.2.0.tgz", + "integrity": "sha512-4RkU9EsI6ZpBve5fseQlGNUWKMa1RLPQ1dnjnQoe07ldfIzcsGb5hC5W0Dm7u423KWzawlrpbjXBrXCEv9zazQ==", + "requires": { + "@aws-sdk/types": "^3.222.0", + "@smithy/util-utf8": "^2.0.0", + "tslib": "^2.6.2" + }, + "dependencies": { + "@smithy/util-utf8": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-2.3.0.tgz", + "integrity": "sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A==", + "requires": { + "@smithy/util-buffer-from": "^2.2.0", + "tslib": "^2.6.2" + } + } + } + }, + "@aws-sdk/client-cognito-identity": { + "version": "3.621.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-cognito-identity/-/client-cognito-identity-3.621.0.tgz", + "integrity": "sha512-FpXia5qFf6ijcNDWenVq+mP9r1LbiW/+52i9wrv2+Afi6Nn1ROf8W7St8WvE9TEZ3t78y+vis4CwqfGts+uiKA==", + "requires": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/client-sso-oidc": "3.621.0", + "@aws-sdk/client-sts": "3.621.0", + "@aws-sdk/core": "3.621.0", + "@aws-sdk/credential-provider-node": "3.621.0", + "@aws-sdk/middleware-host-header": "3.620.0", + "@aws-sdk/middleware-logger": "3.609.0", + "@aws-sdk/middleware-recursion-detection": "3.620.0", + "@aws-sdk/middleware-user-agent": "3.620.0", + "@aws-sdk/region-config-resolver": "3.614.0", + "@aws-sdk/types": "3.609.0", + "@aws-sdk/util-endpoints": "3.614.0", + "@aws-sdk/util-user-agent-browser": "3.609.0", + "@aws-sdk/util-user-agent-node": "3.614.0", + "@smithy/config-resolver": "^3.0.5", + "@smithy/core": "^2.3.1", + "@smithy/fetch-http-handler": "^3.2.4", + "@smithy/hash-node": "^3.0.3", + "@smithy/invalid-dependency": "^3.0.3", + "@smithy/middleware-content-length": "^3.0.5", + "@smithy/middleware-endpoint": "^3.1.0", + "@smithy/middleware-retry": "^3.0.13", + "@smithy/middleware-serde": "^3.0.3", + "@smithy/middleware-stack": "^3.0.3", + "@smithy/node-config-provider": "^3.1.4", + "@smithy/node-http-handler": "^3.1.4", + "@smithy/protocol-http": "^4.1.0", + "@smithy/smithy-client": "^3.1.11", + "@smithy/types": "^3.3.0", + "@smithy/url-parser": "^3.0.3", + "@smithy/util-base64": "^3.0.0", + "@smithy/util-body-length-browser": "^3.0.0", + "@smithy/util-body-length-node": "^3.0.0", + "@smithy/util-defaults-mode-browser": "^3.0.13", + "@smithy/util-defaults-mode-node": "^3.0.13", + "@smithy/util-endpoints": "^2.0.5", + "@smithy/util-middleware": "^3.0.3", + "@smithy/util-retry": "^3.0.3", + "@smithy/util-utf8": "^3.0.0", + "tslib": "^2.6.2" + } + }, + "@aws-sdk/client-sso": { + "version": "3.621.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.621.0.tgz", + "integrity": "sha512-xpKfikN4u0BaUYZA9FGUMkkDmfoIP0Q03+A86WjqDWhcOoqNA1DkHsE4kZ+r064ifkPUfcNuUvlkVTEoBZoFjA==", + "requires": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/core": "3.621.0", + "@aws-sdk/middleware-host-header": "3.620.0", + "@aws-sdk/middleware-logger": "3.609.0", + "@aws-sdk/middleware-recursion-detection": "3.620.0", + "@aws-sdk/middleware-user-agent": "3.620.0", + "@aws-sdk/region-config-resolver": "3.614.0", + "@aws-sdk/types": "3.609.0", + "@aws-sdk/util-endpoints": "3.614.0", + "@aws-sdk/util-user-agent-browser": "3.609.0", + "@aws-sdk/util-user-agent-node": "3.614.0", + "@smithy/config-resolver": "^3.0.5", + "@smithy/core": "^2.3.1", + "@smithy/fetch-http-handler": "^3.2.4", + "@smithy/hash-node": "^3.0.3", + "@smithy/invalid-dependency": "^3.0.3", + "@smithy/middleware-content-length": "^3.0.5", + "@smithy/middleware-endpoint": "^3.1.0", + "@smithy/middleware-retry": "^3.0.13", + "@smithy/middleware-serde": "^3.0.3", + "@smithy/middleware-stack": "^3.0.3", + "@smithy/node-config-provider": "^3.1.4", + "@smithy/node-http-handler": "^3.1.4", + "@smithy/protocol-http": "^4.1.0", + "@smithy/smithy-client": "^3.1.11", + "@smithy/types": "^3.3.0", + "@smithy/url-parser": "^3.0.3", + "@smithy/util-base64": "^3.0.0", + "@smithy/util-body-length-browser": "^3.0.0", + "@smithy/util-body-length-node": "^3.0.0", + "@smithy/util-defaults-mode-browser": "^3.0.13", + "@smithy/util-defaults-mode-node": "^3.0.13", + "@smithy/util-endpoints": "^2.0.5", + "@smithy/util-middleware": "^3.0.3", + "@smithy/util-retry": "^3.0.3", + "@smithy/util-utf8": "^3.0.0", + "tslib": "^2.6.2" + } + }, + "@aws-sdk/client-sts": { + "version": "3.621.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sts/-/client-sts-3.621.0.tgz", + "integrity": "sha512-707uiuReSt+nAx6d0c21xLjLm2lxeKc7padxjv92CIrIocnQSlJPxSCM7r5zBhwiahJA6MNQwmTl2xznU67KgA==", + "requires": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/client-sso-oidc": "3.621.0", + "@aws-sdk/core": "3.621.0", + "@aws-sdk/credential-provider-node": "3.621.0", + "@aws-sdk/middleware-host-header": "3.620.0", + "@aws-sdk/middleware-logger": "3.609.0", + "@aws-sdk/middleware-recursion-detection": "3.620.0", + "@aws-sdk/middleware-user-agent": "3.620.0", + "@aws-sdk/region-config-resolver": "3.614.0", + "@aws-sdk/types": "3.609.0", + "@aws-sdk/util-endpoints": "3.614.0", + "@aws-sdk/util-user-agent-browser": "3.609.0", + "@aws-sdk/util-user-agent-node": "3.614.0", + "@smithy/config-resolver": "^3.0.5", + "@smithy/core": "^2.3.1", + "@smithy/fetch-http-handler": "^3.2.4", + "@smithy/hash-node": "^3.0.3", + "@smithy/invalid-dependency": "^3.0.3", + "@smithy/middleware-content-length": "^3.0.5", + "@smithy/middleware-endpoint": "^3.1.0", + "@smithy/middleware-retry": "^3.0.13", + "@smithy/middleware-serde": "^3.0.3", + "@smithy/middleware-stack": "^3.0.3", + "@smithy/node-config-provider": "^3.1.4", + "@smithy/node-http-handler": "^3.1.4", + "@smithy/protocol-http": "^4.1.0", + "@smithy/smithy-client": "^3.1.11", + "@smithy/types": "^3.3.0", + "@smithy/url-parser": "^3.0.3", + "@smithy/util-base64": "^3.0.0", + "@smithy/util-body-length-browser": "^3.0.0", + "@smithy/util-body-length-node": "^3.0.0", + "@smithy/util-defaults-mode-browser": "^3.0.13", + "@smithy/util-defaults-mode-node": "^3.0.13", + "@smithy/util-endpoints": "^2.0.5", + "@smithy/util-middleware": "^3.0.3", + "@smithy/util-retry": "^3.0.3", + "@smithy/util-utf8": "^3.0.0", + "tslib": "^2.6.2" + } + }, + "@aws-sdk/credential-provider-cognito-identity": { + "version": "3.621.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-cognito-identity/-/credential-provider-cognito-identity-3.621.0.tgz", + "integrity": "sha512-Q+3awvTVJSqIGRjCUQflRwKPKlZ0TfmL3EQHgFLhZZrToeBapEA62+FY+T70aTKAZZZZprlvYeFPtBloNd5ziA==", + "requires": { + "@aws-sdk/client-cognito-identity": "3.621.0", + "@aws-sdk/types": "3.609.0", + "@smithy/property-provider": "^3.1.3", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + } + }, + "@aws-sdk/credential-provider-env": { + "version": "3.620.1", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.620.1.tgz", + "integrity": "sha512-ExuILJ2qLW5ZO+rgkNRj0xiAipKT16Rk77buvPP8csR7kkCflT/gXTyzRe/uzIiETTxM7tr8xuO9MP/DQXqkfg==", + "requires": { + "@aws-sdk/types": "3.609.0", + "@smithy/property-provider": "^3.1.3", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + } + }, + "@aws-sdk/credential-provider-ini": { + "version": "3.621.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.621.0.tgz", + "integrity": "sha512-0EWVnSc+JQn5HLnF5Xv405M8n4zfdx9gyGdpnCmAmFqEDHA8LmBdxJdpUk1Ovp/I5oPANhjojxabIW5f1uU0RA==", + "requires": { + "@aws-sdk/credential-provider-env": "3.620.1", + "@aws-sdk/credential-provider-http": "3.621.0", + "@aws-sdk/credential-provider-process": "3.620.1", + "@aws-sdk/credential-provider-sso": "3.621.0", + "@aws-sdk/credential-provider-web-identity": "3.621.0", + "@aws-sdk/types": "3.609.0", + "@smithy/credential-provider-imds": "^3.2.0", + "@smithy/property-provider": "^3.1.3", + "@smithy/shared-ini-file-loader": "^3.1.4", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + } + }, + "@aws-sdk/credential-provider-node": { + "version": "3.621.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.621.0.tgz", + "integrity": "sha512-4JqpccUgz5Snanpt2+53hbOBbJQrSFq7E1sAAbgY6BKVQUsW5qyXqnjvSF32kDeKa5JpBl3bBWLZl04IadcPHw==", + "requires": { + "@aws-sdk/credential-provider-env": "3.620.1", + "@aws-sdk/credential-provider-http": "3.621.0", + "@aws-sdk/credential-provider-ini": "3.621.0", + "@aws-sdk/credential-provider-process": "3.620.1", + "@aws-sdk/credential-provider-sso": "3.621.0", + "@aws-sdk/credential-provider-web-identity": "3.621.0", + "@aws-sdk/types": "3.609.0", + "@smithy/credential-provider-imds": "^3.2.0", + "@smithy/property-provider": "^3.1.3", + "@smithy/shared-ini-file-loader": "^3.1.4", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + } + }, + "@aws-sdk/credential-provider-process": { + "version": "3.620.1", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.620.1.tgz", + "integrity": "sha512-hWqFMidqLAkaV9G460+1at6qa9vySbjQKKc04p59OT7lZ5cO5VH5S4aI05e+m4j364MBROjjk2ugNvfNf/8ILg==", + "requires": { + "@aws-sdk/types": "3.609.0", + "@smithy/property-provider": "^3.1.3", + "@smithy/shared-ini-file-loader": "^3.1.4", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + } + }, + "@aws-sdk/credential-provider-sso": { + "version": "3.621.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.621.0.tgz", + "integrity": "sha512-Kza0jcFeA/GEL6xJlzR2KFf1PfZKMFnxfGzJzl5yN7EjoGdMijl34KaRyVnfRjnCWcsUpBWKNIDk9WZVMY9yiw==", + "requires": { + "@aws-sdk/client-sso": "3.621.0", + "@aws-sdk/token-providers": "3.614.0", + "@aws-sdk/types": "3.609.0", + "@smithy/property-provider": "^3.1.3", + "@smithy/shared-ini-file-loader": "^3.1.4", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + } + }, + "@aws-sdk/credential-provider-web-identity": { + "version": "3.621.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.621.0.tgz", + "integrity": "sha512-w7ASSyfNvcx7+bYGep3VBgC3K6vEdLmlpjT7nSIHxxQf+WSdvy+HynwJosrpZax0sK5q0D1Jpn/5q+r5lwwW6w==", + "requires": { + "@aws-sdk/types": "3.609.0", + "@smithy/property-provider": "^3.1.3", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + } + }, + "@aws-sdk/middleware-host-header": { + "version": "3.620.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.620.0.tgz", + "integrity": "sha512-VMtPEZwqYrII/oUkffYsNWY9PZ9xpNJpMgmyU0rlDQ25O1c0Hk3fJmZRe6pEkAJ0omD7kLrqGl1DUjQVxpd/Rg==", + "requires": { + "@aws-sdk/types": "3.609.0", + "@smithy/protocol-http": "^4.1.0", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + } + }, + "@aws-sdk/middleware-logger": { + "version": "3.609.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.609.0.tgz", + "integrity": "sha512-S62U2dy4jMDhDFDK5gZ4VxFdWzCtLzwbYyFZx2uvPYTECkepLUfzLic2BHg2Qvtu4QjX+oGE3P/7fwaGIsGNuQ==", + "requires": { + "@aws-sdk/types": "3.609.0", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + } + }, + "@aws-sdk/middleware-recursion-detection": { + "version": "3.620.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.620.0.tgz", + "integrity": "sha512-nh91S7aGK3e/o1ck64sA/CyoFw+gAYj2BDOnoNa6ouyCrVJED96ZXWbhye/fz9SgmNUZR2g7GdVpiLpMKZoI5w==", + "requires": { + "@aws-sdk/types": "3.609.0", + "@smithy/protocol-http": "^4.1.0", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + } + }, + "@aws-sdk/middleware-user-agent": { + "version": "3.620.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.620.0.tgz", + "integrity": "sha512-bvS6etn+KsuL32ubY5D3xNof1qkenpbJXf/ugGXbg0n98DvDFQ/F+SMLxHgbnER5dsKYchNnhmtI6/FC3HFu/A==", + "requires": { + "@aws-sdk/types": "3.609.0", + "@aws-sdk/util-endpoints": "3.614.0", + "@smithy/protocol-http": "^4.1.0", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + } + }, + "@aws-sdk/token-providers": { + "version": "3.614.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.614.0.tgz", + "integrity": "sha512-okItqyY6L9IHdxqs+Z116y5/nda7rHxLvROxtAJdLavWTYDydxrZstImNgGWTeVdmc0xX2gJCI77UYUTQWnhRw==", + "requires": { + "@aws-sdk/types": "3.609.0", + "@smithy/property-provider": "^3.1.3", + "@smithy/shared-ini-file-loader": "^3.1.4", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + } + }, + "@aws-sdk/types": { + "version": "3.609.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.609.0.tgz", + "integrity": "sha512-+Tqnh9w0h2LcrUsdXyT1F8mNhXz+tVYBtP19LpeEGntmvHwa2XzvLUCWpoIAIVsHp5+HdB2X9Sn0KAtmbFXc2Q==", + "requires": { + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + } + }, + "@aws-sdk/util-endpoints": { + "version": "3.614.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.614.0.tgz", + "integrity": "sha512-wK2cdrXHH4oz4IomV/yrGkftU9A+ITB6nFL+rxxyO78is2ifHJpFdV4aqk4LSkXYPi6CXWNru/Dqc7yiKXgJPw==", + "requires": { + "@aws-sdk/types": "3.609.0", + "@smithy/types": "^3.3.0", + "@smithy/util-endpoints": "^2.0.5", + "tslib": "^2.6.2" + } + }, + "@aws-sdk/util-user-agent-browser": { + "version": "3.609.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.609.0.tgz", + "integrity": "sha512-fojPU+mNahzQ0YHYBsx0ZIhmMA96H+ZIZ665ObU9tl+SGdbLneVZVikGve+NmHTQwHzwkFsZYYnVKAkreJLAtA==", + "requires": { + "@aws-sdk/types": "3.609.0", + "@smithy/types": "^3.3.0", + "bowser": "^2.11.0", + "tslib": "^2.6.2" + } + }, + "@aws-sdk/util-user-agent-node": { + "version": "3.614.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.614.0.tgz", + "integrity": "sha512-15ElZT88peoHnq5TEoEtZwoXTXRxNrk60TZNdpl/TUBJ5oNJ9Dqb5Z4ryb8ofN6nm9aFf59GVAerFDz8iUoHBA==", + "requires": { + "@aws-sdk/types": "3.609.0", + "@smithy/node-config-provider": "^3.1.4", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + } + }, + "@smithy/abort-controller": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@smithy/abort-controller/-/abort-controller-3.1.1.tgz", + "integrity": "sha512-MBJBiidoe+0cTFhyxT8g+9g7CeVccLM0IOKKUMCNQ1CNMJ/eIfoo0RTfVrXOONEI1UCN1W+zkiHSbzUNE9dZtQ==", + "requires": { + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + } + }, + "@smithy/config-resolver": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@smithy/config-resolver/-/config-resolver-3.0.5.tgz", + "integrity": "sha512-SkW5LxfkSI1bUC74OtfBbdz+grQXYiPYolyu8VfpLIjEoN/sHVBlLeGXMQ1vX4ejkgfv6sxVbQJ32yF2cl1veA==", + "requires": { + "@smithy/node-config-provider": "^3.1.4", + "@smithy/types": "^3.3.0", + "@smithy/util-config-provider": "^3.0.0", + "@smithy/util-middleware": "^3.0.3", + "tslib": "^2.6.2" + } + }, + "@smithy/credential-provider-imds": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/@smithy/credential-provider-imds/-/credential-provider-imds-3.2.0.tgz", + "integrity": "sha512-0SCIzgd8LYZ9EJxUjLXBmEKSZR/P/w6l7Rz/pab9culE/RWuqelAKGJvn5qUOl8BgX8Yj5HWM50A5hiB/RzsgA==", + "requires": { + "@smithy/node-config-provider": "^3.1.4", + "@smithy/property-provider": "^3.1.3", + "@smithy/types": "^3.3.0", + "@smithy/url-parser": "^3.0.3", + "tslib": "^2.6.2" + } + }, + "@smithy/fetch-http-handler": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-3.2.4.tgz", + "integrity": "sha512-kBprh5Gs5h7ug4nBWZi1FZthdqSM+T7zMmsZxx0IBvWUn7dK3diz2SHn7Bs4dQGFDk8plDv375gzenDoNwrXjg==", + "requires": { + "@smithy/protocol-http": "^4.1.0", + "@smithy/querystring-builder": "^3.0.3", + "@smithy/types": "^3.3.0", + "@smithy/util-base64": "^3.0.0", + "tslib": "^2.6.2" + } + }, + "@smithy/hash-node": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@smithy/hash-node/-/hash-node-3.0.3.tgz", + "integrity": "sha512-2ctBXpPMG+B3BtWSGNnKELJ7SH9e4TNefJS0cd2eSkOOROeBnnVBnAy9LtJ8tY4vUEoe55N4CNPxzbWvR39iBw==", + "requires": { + "@smithy/types": "^3.3.0", + "@smithy/util-buffer-from": "^3.0.0", + "@smithy/util-utf8": "^3.0.0", + "tslib": "^2.6.2" + }, + "dependencies": { + "@smithy/is-array-buffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-3.0.0.tgz", + "integrity": "sha512-+Fsu6Q6C4RSJiy81Y8eApjEB5gVtM+oFKTffg+jSuwtvomJJrhUJBu2zS8wjXSgH/g1MKEWrzyChTBe6clb5FQ==", + "requires": { + "tslib": "^2.6.2" + } + }, + "@smithy/util-buffer-from": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-3.0.0.tgz", + "integrity": "sha512-aEOHCgq5RWFbP+UDPvPot26EJHjOC+bRgse5A8V3FSShqd5E5UN4qc7zkwsvJPPAVsf73QwYcHN1/gt/rtLwQA==", + "requires": { + "@smithy/is-array-buffer": "^3.0.0", + "tslib": "^2.6.2" + } + } + } + }, + "@smithy/invalid-dependency": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@smithy/invalid-dependency/-/invalid-dependency-3.0.3.tgz", + "integrity": "sha512-ID1eL/zpDULmHJbflb864k72/SNOZCADRc9i7Exq3RUNJw6raWUSlFEQ+3PX3EYs++bTxZB2dE9mEHTQLv61tw==", + "requires": { + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + } + }, + "@smithy/is-array-buffer": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-2.2.0.tgz", + "integrity": "sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA==", + "requires": { + "tslib": "^2.6.2" + } + }, + "@smithy/middleware-content-length": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@smithy/middleware-content-length/-/middleware-content-length-3.0.5.tgz", + "integrity": "sha512-ILEzC2eyxx6ncej3zZSwMpB5RJ0zuqH7eMptxC4KN3f+v9bqT8ohssKbhNR78k/2tWW+KS5Spw+tbPF4Ejyqvw==", + "requires": { + "@smithy/protocol-http": "^4.1.0", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + } + }, + "@smithy/middleware-endpoint": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@smithy/middleware-endpoint/-/middleware-endpoint-3.1.0.tgz", + "integrity": "sha512-5y5aiKCEwg9TDPB4yFE7H6tYvGFf1OJHNczeY10/EFF8Ir8jZbNntQJxMWNfeQjC1mxPsaQ6mR9cvQbf+0YeMw==", + "requires": { + "@smithy/middleware-serde": "^3.0.3", + "@smithy/node-config-provider": "^3.1.4", + "@smithy/shared-ini-file-loader": "^3.1.4", + "@smithy/types": "^3.3.0", + "@smithy/url-parser": "^3.0.3", + "@smithy/util-middleware": "^3.0.3", + "tslib": "^2.6.2" + } + }, + "@smithy/middleware-retry": { + "version": "3.0.13", + "resolved": "https://registry.npmjs.org/@smithy/middleware-retry/-/middleware-retry-3.0.13.tgz", + "integrity": "sha512-zvCLfaRYCaUmjbF2yxShGZdolSHft7NNCTA28HVN9hKcEbOH+g5irr1X9s+in8EpambclGnevZY4A3lYpvDCFw==", + "requires": { + "@smithy/node-config-provider": "^3.1.4", + "@smithy/protocol-http": "^4.1.0", + "@smithy/service-error-classification": "^3.0.3", + "@smithy/smithy-client": "^3.1.11", + "@smithy/types": "^3.3.0", + "@smithy/util-middleware": "^3.0.3", + "@smithy/util-retry": "^3.0.3", + "tslib": "^2.6.2", + "uuid": "^9.0.1" + } + }, + "@smithy/middleware-serde": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@smithy/middleware-serde/-/middleware-serde-3.0.3.tgz", + "integrity": "sha512-puUbyJQBcg9eSErFXjKNiGILJGtiqmuuNKEYNYfUD57fUl4i9+mfmThtQhvFXU0hCVG0iEJhvQUipUf+/SsFdA==", + "requires": { + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + } + }, + "@smithy/middleware-stack": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@smithy/middleware-stack/-/middleware-stack-3.0.3.tgz", + "integrity": "sha512-r4klY9nFudB0r9UdSMaGSyjyQK5adUyPnQN/ZM6M75phTxOdnc/AhpvGD1fQUvgmqjQEBGCwpnPbDm8pH5PapA==", + "requires": { + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + } + }, + "@smithy/node-config-provider": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/@smithy/node-config-provider/-/node-config-provider-3.1.4.tgz", + "integrity": "sha512-YvnElQy8HR4vDcAjoy7Xkx9YT8xZP4cBXcbJSgm/kxmiQu08DwUwj8rkGnyoJTpfl/3xYHH+d8zE+eHqoDCSdQ==", + "requires": { + "@smithy/property-provider": "^3.1.3", + "@smithy/shared-ini-file-loader": "^3.1.4", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + } + }, + "@smithy/node-http-handler": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-3.1.4.tgz", + "integrity": "sha512-+UmxgixgOr/yLsUxcEKGH0fMNVteJFGkmRltYFHnBMlogyFdpzn2CwqWmxOrfJELhV34v0WSlaqG1UtE1uXlJg==", + "requires": { + "@smithy/abort-controller": "^3.1.1", + "@smithy/protocol-http": "^4.1.0", + "@smithy/querystring-builder": "^3.0.3", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + } + }, + "@smithy/property-provider": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/@smithy/property-provider/-/property-provider-3.1.3.tgz", + "integrity": "sha512-zahyOVR9Q4PEoguJ/NrFP4O7SMAfYO1HLhB18M+q+Z4KFd4V2obiMnlVoUFzFLSPeVt1POyNWneHHrZaTMoc/g==", + "requires": { + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + } + }, + "@smithy/protocol-http": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-4.1.0.tgz", + "integrity": "sha512-dPVoHYQ2wcHooGXg3LQisa1hH0e4y0pAddPMeeUPipI1tEOqL6A4N0/G7abeq+K8wrwSgjk4C0wnD1XZpJm5aA==", + "requires": { + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + } + }, + "@smithy/querystring-builder": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@smithy/querystring-builder/-/querystring-builder-3.0.3.tgz", + "integrity": "sha512-vyWckeUeesFKzCDaRwWLUA1Xym9McaA6XpFfAK5qI9DKJ4M33ooQGqvM4J+LalH4u/Dq9nFiC8U6Qn1qi0+9zw==", + "requires": { + "@smithy/types": "^3.3.0", + "@smithy/util-uri-escape": "^3.0.0", + "tslib": "^2.6.2" + } + }, + "@smithy/querystring-parser": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@smithy/querystring-parser/-/querystring-parser-3.0.3.tgz", + "integrity": "sha512-zahM1lQv2YjmznnfQsWbYojFe55l0SLG/988brlLv1i8z3dubloLF+75ATRsqPBboUXsW6I9CPGE5rQgLfY0vQ==", + "requires": { + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + } + }, + "@smithy/service-error-classification": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@smithy/service-error-classification/-/service-error-classification-3.0.3.tgz", + "integrity": "sha512-Jn39sSl8cim/VlkLsUhRFq/dKDnRUFlfRkvhOJaUbLBXUsLRLNf9WaxDv/z9BjuQ3A6k/qE8af1lsqcwm7+DaQ==", + "requires": { + "@smithy/types": "^3.3.0" + } + }, + "@smithy/shared-ini-file-loader": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/@smithy/shared-ini-file-loader/-/shared-ini-file-loader-3.1.4.tgz", + "integrity": "sha512-qMxS4hBGB8FY2GQqshcRUy1K6k8aBWP5vwm8qKkCT3A9K2dawUwOIJfqh9Yste/Bl0J2lzosVyrXDj68kLcHXQ==", + "requires": { + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + } + }, + "@smithy/smithy-client": { + "version": "3.1.11", + "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-3.1.11.tgz", + "integrity": "sha512-l0BpyYkciNyMaS+PnFFz4aO5sBcXvGLoJd7mX9xrMBIm2nIQBVvYgp2ZpPDMzwjKCavsXu06iuCm0F6ZJZc6yQ==", + "requires": { + "@smithy/middleware-endpoint": "^3.1.0", + "@smithy/middleware-stack": "^3.0.3", + "@smithy/protocol-http": "^4.1.0", + "@smithy/types": "^3.3.0", + "@smithy/util-stream": "^3.1.3", + "tslib": "^2.6.2" + } + }, + "@smithy/types": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-3.3.0.tgz", + "integrity": "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA==", + "requires": { + "tslib": "^2.6.2" + } + }, + "@smithy/url-parser": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@smithy/url-parser/-/url-parser-3.0.3.tgz", + "integrity": "sha512-pw3VtZtX2rg+s6HMs6/+u9+hu6oY6U7IohGhVNnjbgKy86wcIsSZwgHrFR+t67Uyxvp4Xz3p3kGXXIpTNisq8A==", + "requires": { + "@smithy/querystring-parser": "^3.0.3", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + } + }, + "@smithy/util-base64": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-base64/-/util-base64-3.0.0.tgz", + "integrity": "sha512-Kxvoh5Qtt0CDsfajiZOCpJxgtPHXOKwmM+Zy4waD43UoEMA+qPxxa98aE/7ZhdnBFZFXMOiBR5xbcaMhLtznQQ==", + "requires": { + "@smithy/util-buffer-from": "^3.0.0", + "@smithy/util-utf8": "^3.0.0", + "tslib": "^2.6.2" + }, + "dependencies": { + "@smithy/is-array-buffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-3.0.0.tgz", + "integrity": "sha512-+Fsu6Q6C4RSJiy81Y8eApjEB5gVtM+oFKTffg+jSuwtvomJJrhUJBu2zS8wjXSgH/g1MKEWrzyChTBe6clb5FQ==", + "requires": { + "tslib": "^2.6.2" + } + }, + "@smithy/util-buffer-from": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-3.0.0.tgz", + "integrity": "sha512-aEOHCgq5RWFbP+UDPvPot26EJHjOC+bRgse5A8V3FSShqd5E5UN4qc7zkwsvJPPAVsf73QwYcHN1/gt/rtLwQA==", + "requires": { + "@smithy/is-array-buffer": "^3.0.0", + "tslib": "^2.6.2" + } + } + } + }, + "@smithy/util-body-length-browser": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-body-length-browser/-/util-body-length-browser-3.0.0.tgz", + "integrity": "sha512-cbjJs2A1mLYmqmyVl80uoLTJhAcfzMOyPgjwAYusWKMdLeNtzmMz9YxNl3/jRLoxSS3wkqkf0jwNdtXWtyEBaQ==", + "requires": { + "tslib": "^2.6.2" + } + }, + "@smithy/util-body-length-node": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-body-length-node/-/util-body-length-node-3.0.0.tgz", + "integrity": "sha512-Tj7pZ4bUloNUP6PzwhN7K386tmSmEET9QtQg0TgdNOnxhZvCssHji+oZTUIuzxECRfG8rdm2PMw2WCFs6eIYkA==", + "requires": { + "tslib": "^2.6.2" + } + }, + "@smithy/util-buffer-from": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-2.2.0.tgz", + "integrity": "sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA==", + "requires": { + "@smithy/is-array-buffer": "^2.2.0", + "tslib": "^2.6.2" + } + }, + "@smithy/util-config-provider": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-config-provider/-/util-config-provider-3.0.0.tgz", + "integrity": "sha512-pbjk4s0fwq3Di/ANL+rCvJMKM5bzAQdE5S/6RL5NXgMExFAi6UgQMPOm5yPaIWPpr+EOXKXRonJ3FoxKf4mCJQ==", + "requires": { + "tslib": "^2.6.2" + } + }, + "@smithy/util-defaults-mode-browser": { + "version": "3.0.13", + "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-3.0.13.tgz", + "integrity": "sha512-ZIRSUsnnMRStOP6OKtW+gCSiVFkwnfQF2xtf32QKAbHR6ACjhbAybDvry+3L5qQYdh3H6+7yD/AiUE45n8mTTw==", + "requires": { + "@smithy/property-provider": "^3.1.3", + "@smithy/smithy-client": "^3.1.11", + "@smithy/types": "^3.3.0", + "bowser": "^2.11.0", + "tslib": "^2.6.2" + } + }, + "@smithy/util-defaults-mode-node": { + "version": "3.0.13", + "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-3.0.13.tgz", + "integrity": "sha512-voUa8TFJGfD+U12tlNNLCDlXibt9vRdNzRX45Onk/WxZe7TS+hTOZouEZRa7oARGicdgeXvt1A0W45qLGYdy+g==", + "requires": { + "@smithy/config-resolver": "^3.0.5", + "@smithy/credential-provider-imds": "^3.2.0", + "@smithy/node-config-provider": "^3.1.4", + "@smithy/property-provider": "^3.1.3", + "@smithy/smithy-client": "^3.1.11", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + } + }, + "@smithy/util-hex-encoding": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-hex-encoding/-/util-hex-encoding-3.0.0.tgz", + "integrity": "sha512-eFndh1WEK5YMUYvy3lPlVmYY/fZcQE1D8oSf41Id2vCeIkKJXPcYDCZD+4+xViI6b1XSd7tE+s5AmXzz5ilabQ==", + "requires": { + "tslib": "^2.6.2" + } + }, + "@smithy/util-middleware": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@smithy/util-middleware/-/util-middleware-3.0.3.tgz", + "integrity": "sha512-l+StyYYK/eO3DlVPbU+4Bi06Jjal+PFLSMmlWM1BEwyLxZ3aKkf1ROnoIakfaA7mC6uw3ny7JBkau4Yc+5zfWw==", + "requires": { + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + } + }, + "@smithy/util-retry": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@smithy/util-retry/-/util-retry-3.0.3.tgz", + "integrity": "sha512-AFw+hjpbtVApzpNDhbjNG5NA3kyoMs7vx0gsgmlJF4s+yz1Zlepde7J58zpIRIsdjc+emhpAITxA88qLkPF26w==", + "requires": { + "@smithy/service-error-classification": "^3.0.3", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + } + }, + "@smithy/util-stream": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/@smithy/util-stream/-/util-stream-3.1.3.tgz", + "integrity": "sha512-FIv/bRhIlAxC0U7xM1BCnF2aDRPq0UaelqBHkM2lsCp26mcBbgI0tCVTv+jGdsQLUmAMybua/bjDsSu8RQHbmw==", + "requires": { + "@smithy/fetch-http-handler": "^3.2.4", + "@smithy/node-http-handler": "^3.1.4", + "@smithy/types": "^3.3.0", + "@smithy/util-base64": "^3.0.0", + "@smithy/util-buffer-from": "^3.0.0", + "@smithy/util-hex-encoding": "^3.0.0", + "@smithy/util-utf8": "^3.0.0", + "tslib": "^2.6.2" + }, + "dependencies": { + "@smithy/is-array-buffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-3.0.0.tgz", + "integrity": "sha512-+Fsu6Q6C4RSJiy81Y8eApjEB5gVtM+oFKTffg+jSuwtvomJJrhUJBu2zS8wjXSgH/g1MKEWrzyChTBe6clb5FQ==", + "requires": { + "tslib": "^2.6.2" + } + }, + "@smithy/util-buffer-from": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-3.0.0.tgz", + "integrity": "sha512-aEOHCgq5RWFbP+UDPvPot26EJHjOC+bRgse5A8V3FSShqd5E5UN4qc7zkwsvJPPAVsf73QwYcHN1/gt/rtLwQA==", + "requires": { + "@smithy/is-array-buffer": "^3.0.0", + "tslib": "^2.6.2" + } + } + } + }, + "@smithy/util-uri-escape": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-uri-escape/-/util-uri-escape-3.0.0.tgz", + "integrity": "sha512-LqR7qYLgZTD7nWLBecUi4aqolw8Mhza9ArpNEQ881MJJIU2sE5iHCK6TdyqqzcDLy0OPe10IY4T8ctVdtynubg==", + "requires": { + "tslib": "^2.6.2" + } + }, + "@smithy/util-utf8": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-3.0.0.tgz", + "integrity": "sha512-rUeT12bxFnplYDe815GXbq/oixEGHfRFFtcTF3YdDi/JaENIM6aSYYLJydG83UNzLXeRI5K8abYd/8Sp/QM0kA==", + "requires": { + "@smithy/util-buffer-from": "^3.0.0", + "tslib": "^2.6.2" + }, + "dependencies": { + "@smithy/is-array-buffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-3.0.0.tgz", + "integrity": "sha512-+Fsu6Q6C4RSJiy81Y8eApjEB5gVtM+oFKTffg+jSuwtvomJJrhUJBu2zS8wjXSgH/g1MKEWrzyChTBe6clb5FQ==", + "requires": { + "tslib": "^2.6.2" + } + }, + "@smithy/util-buffer-from": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-3.0.0.tgz", + "integrity": "sha512-aEOHCgq5RWFbP+UDPvPot26EJHjOC+bRgse5A8V3FSShqd5E5UN4qc7zkwsvJPPAVsf73QwYcHN1/gt/rtLwQA==", + "requires": { + "@smithy/is-array-buffer": "^3.0.0", + "tslib": "^2.6.2" + } + } + } + }, + "uuid": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", + "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==" + } } }, - "@smithy/util-defaults-mode-node": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-2.0.5.tgz", - "integrity": "sha512-M07t99rWasXt+IaDZDyP3BkcoEm/mgIE1RIMASrE49LKSNxaVN7PVcgGc77+4uu2kzBAyqJKy79pgtezuknyjQ==", - "optional": true, + "@aws-sdk/region-config-resolver": { + "version": "3.614.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/region-config-resolver/-/region-config-resolver-3.614.0.tgz", + "integrity": "sha512-vDCeMXvic/LU0KFIUjpC3RiSTIkkvESsEfbVHiHH0YINfl8HnEqR5rj+L8+phsCeVg2+LmYwYxd5NRz4PHxt5g==", "requires": { - "@smithy/config-resolver": "^2.0.5", - "@smithy/credential-provider-imds": "^2.0.5", - "@smithy/node-config-provider": "^2.0.5", - "@smithy/property-provider": "^2.0.5", - "@smithy/types": "^2.2.2", - "tslib": "^2.5.0" + "@aws-sdk/types": "3.609.0", + "@smithy/node-config-provider": "^3.1.4", + "@smithy/types": "^3.3.0", + "@smithy/util-config-provider": "^3.0.0", + "@smithy/util-middleware": "^3.0.3", + "tslib": "^2.6.2" + }, + "dependencies": { + "@aws-sdk/types": { + "version": "3.609.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.609.0.tgz", + "integrity": "sha512-+Tqnh9w0h2LcrUsdXyT1F8mNhXz+tVYBtP19LpeEGntmvHwa2XzvLUCWpoIAIVsHp5+HdB2X9Sn0KAtmbFXc2Q==", + "requires": { + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + } + }, + "@smithy/node-config-provider": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/@smithy/node-config-provider/-/node-config-provider-3.1.4.tgz", + "integrity": "sha512-YvnElQy8HR4vDcAjoy7Xkx9YT8xZP4cBXcbJSgm/kxmiQu08DwUwj8rkGnyoJTpfl/3xYHH+d8zE+eHqoDCSdQ==", + "requires": { + "@smithy/property-provider": "^3.1.3", + "@smithy/shared-ini-file-loader": "^3.1.4", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + } + }, + "@smithy/property-provider": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/@smithy/property-provider/-/property-provider-3.1.3.tgz", + "integrity": "sha512-zahyOVR9Q4PEoguJ/NrFP4O7SMAfYO1HLhB18M+q+Z4KFd4V2obiMnlVoUFzFLSPeVt1POyNWneHHrZaTMoc/g==", + "requires": { + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + } + }, + "@smithy/shared-ini-file-loader": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/@smithy/shared-ini-file-loader/-/shared-ini-file-loader-3.1.4.tgz", + "integrity": "sha512-qMxS4hBGB8FY2GQqshcRUy1K6k8aBWP5vwm8qKkCT3A9K2dawUwOIJfqh9Yste/Bl0J2lzosVyrXDj68kLcHXQ==", + "requires": { + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + } + }, + "@smithy/types": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-3.3.0.tgz", + "integrity": "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA==", + "requires": { + "tslib": "^2.6.2" + } + }, + "@smithy/util-config-provider": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-config-provider/-/util-config-provider-3.0.0.tgz", + "integrity": "sha512-pbjk4s0fwq3Di/ANL+rCvJMKM5bzAQdE5S/6RL5NXgMExFAi6UgQMPOm5yPaIWPpr+EOXKXRonJ3FoxKf4mCJQ==", + "requires": { + "tslib": "^2.6.2" + } + }, + "@smithy/util-middleware": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@smithy/util-middleware/-/util-middleware-3.0.3.tgz", + "integrity": "sha512-l+StyYYK/eO3DlVPbU+4Bi06Jjal+PFLSMmlWM1BEwyLxZ3aKkf1ROnoIakfaA7mC6uw3ny7JBkau4Yc+5zfWw==", + "requires": { + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + } + } } }, - "@smithy/util-hex-encoding": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@smithy/util-hex-encoding/-/util-hex-encoding-2.0.0.tgz", - "integrity": "sha512-c5xY+NUnFqG6d7HFh1IFfrm3mGl29lC+vF+geHv4ToiuJCBmIfzx6IeHLg+OgRdPFKDXIw6pvi+p3CsscaMcMA==", - "optional": true, + "@aws-sdk/util-locate-window": { + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-locate-window/-/util-locate-window-3.310.0.tgz", + "integrity": "sha512-qo2t/vBTnoXpjKxlsC2e1gBrRm80M3bId27r0BRB2VniSSe7bL1mmzM+/HFtujm0iAxtPM+aLEflLJlJeDPg0w==", "requires": { "tslib": "^2.5.0" } }, - "@smithy/util-middleware": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@smithy/util-middleware/-/util-middleware-2.0.0.tgz", - "integrity": "sha512-eCWX4ECuDHn1wuyyDdGdUWnT4OGyIzV0LN1xRttBFMPI9Ff/4heSHVxneyiMtOB//zpXWCha1/SWHJOZstG7kA==", + "@mongodb-js/saslprep": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@mongodb-js/saslprep/-/saslprep-1.1.0.tgz", + "integrity": "sha512-Xfijy7HvfzzqiOAhAepF4SGN5e9leLkMvg/OPOF97XemjfVCYN/oWa75wnkc6mltMSTwY+XlbhWgUOJmkFspSw==", "optional": true, "requires": { - "tslib": "^2.5.0" + "sparse-bitfield": "^3.0.3" } }, - "@smithy/util-retry": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@smithy/util-retry/-/util-retry-2.0.0.tgz", - "integrity": "sha512-/dvJ8afrElasuiiIttRJeoS2sy8YXpksQwiM/TcepqdRVp7u4ejd9C4IQURHNjlfPUT7Y6lCDSa2zQJbdHhVTg==", - "optional": true, - "requires": { - "@smithy/service-error-classification": "^2.0.0", - "tslib": "^2.5.0" + "@smithy/core": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/@smithy/core/-/core-2.3.1.tgz", + "integrity": "sha512-BC7VMXx/1BCmRPCVzzn4HGWAtsrb7/0758EtwOGFJQrlSwJBEjCcDLNZLFoL/68JexYa2s+KmgL/UfmXdG6v1w==", + "requires": { + "@smithy/middleware-endpoint": "^3.1.0", + "@smithy/middleware-retry": "^3.0.13", + "@smithy/middleware-serde": "^3.0.3", + "@smithy/protocol-http": "^4.1.0", + "@smithy/smithy-client": "^3.1.11", + "@smithy/types": "^3.3.0", + "@smithy/util-middleware": "^3.0.3", + "tslib": "^2.6.2" + }, + "dependencies": { + "@smithy/abort-controller": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@smithy/abort-controller/-/abort-controller-3.1.1.tgz", + "integrity": "sha512-MBJBiidoe+0cTFhyxT8g+9g7CeVccLM0IOKKUMCNQ1CNMJ/eIfoo0RTfVrXOONEI1UCN1W+zkiHSbzUNE9dZtQ==", + "requires": { + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + } + }, + "@smithy/fetch-http-handler": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-3.2.4.tgz", + "integrity": "sha512-kBprh5Gs5h7ug4nBWZi1FZthdqSM+T7zMmsZxx0IBvWUn7dK3diz2SHn7Bs4dQGFDk8plDv375gzenDoNwrXjg==", + "requires": { + "@smithy/protocol-http": "^4.1.0", + "@smithy/querystring-builder": "^3.0.3", + "@smithy/types": "^3.3.0", + "@smithy/util-base64": "^3.0.0", + "tslib": "^2.6.2" + } + }, + "@smithy/is-array-buffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-3.0.0.tgz", + "integrity": "sha512-+Fsu6Q6C4RSJiy81Y8eApjEB5gVtM+oFKTffg+jSuwtvomJJrhUJBu2zS8wjXSgH/g1MKEWrzyChTBe6clb5FQ==", + "requires": { + "tslib": "^2.6.2" + } + }, + "@smithy/middleware-endpoint": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@smithy/middleware-endpoint/-/middleware-endpoint-3.1.0.tgz", + "integrity": "sha512-5y5aiKCEwg9TDPB4yFE7H6tYvGFf1OJHNczeY10/EFF8Ir8jZbNntQJxMWNfeQjC1mxPsaQ6mR9cvQbf+0YeMw==", + "requires": { + "@smithy/middleware-serde": "^3.0.3", + "@smithy/node-config-provider": "^3.1.4", + "@smithy/shared-ini-file-loader": "^3.1.4", + "@smithy/types": "^3.3.0", + "@smithy/url-parser": "^3.0.3", + "@smithy/util-middleware": "^3.0.3", + "tslib": "^2.6.2" + } + }, + "@smithy/middleware-retry": { + "version": "3.0.13", + "resolved": "https://registry.npmjs.org/@smithy/middleware-retry/-/middleware-retry-3.0.13.tgz", + "integrity": "sha512-zvCLfaRYCaUmjbF2yxShGZdolSHft7NNCTA28HVN9hKcEbOH+g5irr1X9s+in8EpambclGnevZY4A3lYpvDCFw==", + "requires": { + "@smithy/node-config-provider": "^3.1.4", + "@smithy/protocol-http": "^4.1.0", + "@smithy/service-error-classification": "^3.0.3", + "@smithy/smithy-client": "^3.1.11", + "@smithy/types": "^3.3.0", + "@smithy/util-middleware": "^3.0.3", + "@smithy/util-retry": "^3.0.3", + "tslib": "^2.6.2", + "uuid": "^9.0.1" + } + }, + "@smithy/middleware-serde": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@smithy/middleware-serde/-/middleware-serde-3.0.3.tgz", + "integrity": "sha512-puUbyJQBcg9eSErFXjKNiGILJGtiqmuuNKEYNYfUD57fUl4i9+mfmThtQhvFXU0hCVG0iEJhvQUipUf+/SsFdA==", + "requires": { + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + } + }, + "@smithy/middleware-stack": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@smithy/middleware-stack/-/middleware-stack-3.0.3.tgz", + "integrity": "sha512-r4klY9nFudB0r9UdSMaGSyjyQK5adUyPnQN/ZM6M75phTxOdnc/AhpvGD1fQUvgmqjQEBGCwpnPbDm8pH5PapA==", + "requires": { + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + } + }, + "@smithy/node-config-provider": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/@smithy/node-config-provider/-/node-config-provider-3.1.4.tgz", + "integrity": "sha512-YvnElQy8HR4vDcAjoy7Xkx9YT8xZP4cBXcbJSgm/kxmiQu08DwUwj8rkGnyoJTpfl/3xYHH+d8zE+eHqoDCSdQ==", + "requires": { + "@smithy/property-provider": "^3.1.3", + "@smithy/shared-ini-file-loader": "^3.1.4", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + } + }, + "@smithy/node-http-handler": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-3.1.4.tgz", + "integrity": "sha512-+UmxgixgOr/yLsUxcEKGH0fMNVteJFGkmRltYFHnBMlogyFdpzn2CwqWmxOrfJELhV34v0WSlaqG1UtE1uXlJg==", + "requires": { + "@smithy/abort-controller": "^3.1.1", + "@smithy/protocol-http": "^4.1.0", + "@smithy/querystring-builder": "^3.0.3", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + } + }, + "@smithy/property-provider": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/@smithy/property-provider/-/property-provider-3.1.3.tgz", + "integrity": "sha512-zahyOVR9Q4PEoguJ/NrFP4O7SMAfYO1HLhB18M+q+Z4KFd4V2obiMnlVoUFzFLSPeVt1POyNWneHHrZaTMoc/g==", + "requires": { + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + } + }, + "@smithy/protocol-http": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-4.1.0.tgz", + "integrity": "sha512-dPVoHYQ2wcHooGXg3LQisa1hH0e4y0pAddPMeeUPipI1tEOqL6A4N0/G7abeq+K8wrwSgjk4C0wnD1XZpJm5aA==", + "requires": { + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + } + }, + "@smithy/querystring-builder": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@smithy/querystring-builder/-/querystring-builder-3.0.3.tgz", + "integrity": "sha512-vyWckeUeesFKzCDaRwWLUA1Xym9McaA6XpFfAK5qI9DKJ4M33ooQGqvM4J+LalH4u/Dq9nFiC8U6Qn1qi0+9zw==", + "requires": { + "@smithy/types": "^3.3.0", + "@smithy/util-uri-escape": "^3.0.0", + "tslib": "^2.6.2" + } + }, + "@smithy/querystring-parser": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@smithy/querystring-parser/-/querystring-parser-3.0.3.tgz", + "integrity": "sha512-zahM1lQv2YjmznnfQsWbYojFe55l0SLG/988brlLv1i8z3dubloLF+75ATRsqPBboUXsW6I9CPGE5rQgLfY0vQ==", + "requires": { + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + } + }, + "@smithy/service-error-classification": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@smithy/service-error-classification/-/service-error-classification-3.0.3.tgz", + "integrity": "sha512-Jn39sSl8cim/VlkLsUhRFq/dKDnRUFlfRkvhOJaUbLBXUsLRLNf9WaxDv/z9BjuQ3A6k/qE8af1lsqcwm7+DaQ==", + "requires": { + "@smithy/types": "^3.3.0" + } + }, + "@smithy/shared-ini-file-loader": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/@smithy/shared-ini-file-loader/-/shared-ini-file-loader-3.1.4.tgz", + "integrity": "sha512-qMxS4hBGB8FY2GQqshcRUy1K6k8aBWP5vwm8qKkCT3A9K2dawUwOIJfqh9Yste/Bl0J2lzosVyrXDj68kLcHXQ==", + "requires": { + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + } + }, + "@smithy/smithy-client": { + "version": "3.1.11", + "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-3.1.11.tgz", + "integrity": "sha512-l0BpyYkciNyMaS+PnFFz4aO5sBcXvGLoJd7mX9xrMBIm2nIQBVvYgp2ZpPDMzwjKCavsXu06iuCm0F6ZJZc6yQ==", + "requires": { + "@smithy/middleware-endpoint": "^3.1.0", + "@smithy/middleware-stack": "^3.0.3", + "@smithy/protocol-http": "^4.1.0", + "@smithy/types": "^3.3.0", + "@smithy/util-stream": "^3.1.3", + "tslib": "^2.6.2" + } + }, + "@smithy/types": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-3.3.0.tgz", + "integrity": "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA==", + "requires": { + "tslib": "^2.6.2" + } + }, + "@smithy/url-parser": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@smithy/url-parser/-/url-parser-3.0.3.tgz", + "integrity": "sha512-pw3VtZtX2rg+s6HMs6/+u9+hu6oY6U7IohGhVNnjbgKy86wcIsSZwgHrFR+t67Uyxvp4Xz3p3kGXXIpTNisq8A==", + "requires": { + "@smithy/querystring-parser": "^3.0.3", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + } + }, + "@smithy/util-base64": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-base64/-/util-base64-3.0.0.tgz", + "integrity": "sha512-Kxvoh5Qtt0CDsfajiZOCpJxgtPHXOKwmM+Zy4waD43UoEMA+qPxxa98aE/7ZhdnBFZFXMOiBR5xbcaMhLtznQQ==", + "requires": { + "@smithy/util-buffer-from": "^3.0.0", + "@smithy/util-utf8": "^3.0.0", + "tslib": "^2.6.2" + } + }, + "@smithy/util-buffer-from": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-3.0.0.tgz", + "integrity": "sha512-aEOHCgq5RWFbP+UDPvPot26EJHjOC+bRgse5A8V3FSShqd5E5UN4qc7zkwsvJPPAVsf73QwYcHN1/gt/rtLwQA==", + "requires": { + "@smithy/is-array-buffer": "^3.0.0", + "tslib": "^2.6.2" + } + }, + "@smithy/util-hex-encoding": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-hex-encoding/-/util-hex-encoding-3.0.0.tgz", + "integrity": "sha512-eFndh1WEK5YMUYvy3lPlVmYY/fZcQE1D8oSf41Id2vCeIkKJXPcYDCZD+4+xViI6b1XSd7tE+s5AmXzz5ilabQ==", + "requires": { + "tslib": "^2.6.2" + } + }, + "@smithy/util-middleware": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@smithy/util-middleware/-/util-middleware-3.0.3.tgz", + "integrity": "sha512-l+StyYYK/eO3DlVPbU+4Bi06Jjal+PFLSMmlWM1BEwyLxZ3aKkf1ROnoIakfaA7mC6uw3ny7JBkau4Yc+5zfWw==", + "requires": { + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + } + }, + "@smithy/util-retry": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@smithy/util-retry/-/util-retry-3.0.3.tgz", + "integrity": "sha512-AFw+hjpbtVApzpNDhbjNG5NA3kyoMs7vx0gsgmlJF4s+yz1Zlepde7J58zpIRIsdjc+emhpAITxA88qLkPF26w==", + "requires": { + "@smithy/service-error-classification": "^3.0.3", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + } + }, + "@smithy/util-stream": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/@smithy/util-stream/-/util-stream-3.1.3.tgz", + "integrity": "sha512-FIv/bRhIlAxC0U7xM1BCnF2aDRPq0UaelqBHkM2lsCp26mcBbgI0tCVTv+jGdsQLUmAMybua/bjDsSu8RQHbmw==", + "requires": { + "@smithy/fetch-http-handler": "^3.2.4", + "@smithy/node-http-handler": "^3.1.4", + "@smithy/types": "^3.3.0", + "@smithy/util-base64": "^3.0.0", + "@smithy/util-buffer-from": "^3.0.0", + "@smithy/util-hex-encoding": "^3.0.0", + "@smithy/util-utf8": "^3.0.0", + "tslib": "^2.6.2" + } + }, + "@smithy/util-uri-escape": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-uri-escape/-/util-uri-escape-3.0.0.tgz", + "integrity": "sha512-LqR7qYLgZTD7nWLBecUi4aqolw8Mhza9ArpNEQ881MJJIU2sE5iHCK6TdyqqzcDLy0OPe10IY4T8ctVdtynubg==", + "requires": { + "tslib": "^2.6.2" + } + }, + "@smithy/util-utf8": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-3.0.0.tgz", + "integrity": "sha512-rUeT12bxFnplYDe815GXbq/oixEGHfRFFtcTF3YdDi/JaENIM6aSYYLJydG83UNzLXeRI5K8abYd/8Sp/QM0kA==", + "requires": { + "@smithy/util-buffer-from": "^3.0.0", + "tslib": "^2.6.2" + } + }, + "uuid": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", + "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==" + } } }, - "@smithy/util-stream": { + "@smithy/util-endpoints": { "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@smithy/util-stream/-/util-stream-2.0.5.tgz", - "integrity": "sha512-ylx27GwI05xLpYQ4hDIfS15vm+wYjNN0Sc2P0FxuzgRe8v0BOLHppGIQ+Bezcynk8C9nUzsUue3TmtRhjut43g==", - "optional": true, - "requires": { - "@smithy/fetch-http-handler": "^2.0.5", - "@smithy/node-http-handler": "^2.0.5", - "@smithy/types": "^2.2.2", - "@smithy/util-base64": "^2.0.0", - "@smithy/util-buffer-from": "^2.0.0", - "@smithy/util-hex-encoding": "^2.0.0", - "@smithy/util-utf8": "^2.0.0", - "tslib": "^2.5.0" - } - }, - "@smithy/util-uri-escape": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@smithy/util-uri-escape/-/util-uri-escape-2.0.0.tgz", - "integrity": "sha512-ebkxsqinSdEooQduuk9CbKcI+wheijxEb3utGXkCoYQkJnwTnLbH1JXGimJtUkQwNQbsbuYwG2+aFVyZf5TLaw==", - "optional": true, - "requires": { - "tslib": "^2.5.0" - } - }, - "@smithy/util-utf8": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-2.0.0.tgz", - "integrity": "sha512-rctU1VkziY84n5OXe3bPNpKR001ZCME2JCaBBFgtiM2hfKbHFudc/BkMuPab8hRbLd0j3vbnBTTZ1igBf0wgiQ==", - "optional": true, + "resolved": "https://registry.npmjs.org/@smithy/util-endpoints/-/util-endpoints-2.0.5.tgz", + "integrity": "sha512-ReQP0BWihIE68OAblC/WQmDD40Gx+QY1Ez8mTdFMXpmjfxSyz2fVQu3A4zXRfQU9sZXtewk3GmhfOHswvX+eNg==", "requires": { - "@smithy/util-buffer-from": "^2.0.0", - "tslib": "^2.5.0" + "@smithy/node-config-provider": "^3.1.4", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + }, + "dependencies": { + "@smithy/node-config-provider": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/@smithy/node-config-provider/-/node-config-provider-3.1.4.tgz", + "integrity": "sha512-YvnElQy8HR4vDcAjoy7Xkx9YT8xZP4cBXcbJSgm/kxmiQu08DwUwj8rkGnyoJTpfl/3xYHH+d8zE+eHqoDCSdQ==", + "requires": { + "@smithy/property-provider": "^3.1.3", + "@smithy/shared-ini-file-loader": "^3.1.4", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + } + }, + "@smithy/property-provider": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/@smithy/property-provider/-/property-provider-3.1.3.tgz", + "integrity": "sha512-zahyOVR9Q4PEoguJ/NrFP4O7SMAfYO1HLhB18M+q+Z4KFd4V2obiMnlVoUFzFLSPeVt1POyNWneHHrZaTMoc/g==", + "requires": { + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + } + }, + "@smithy/shared-ini-file-loader": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/@smithy/shared-ini-file-loader/-/shared-ini-file-loader-3.1.4.tgz", + "integrity": "sha512-qMxS4hBGB8FY2GQqshcRUy1K6k8aBWP5vwm8qKkCT3A9K2dawUwOIJfqh9Yste/Bl0J2lzosVyrXDj68kLcHXQ==", + "requires": { + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + } + }, + "@smithy/types": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-3.3.0.tgz", + "integrity": "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA==", + "requires": { + "tslib": "^2.6.2" + } + } } }, "@srfnstack/spliffy": { @@ -1032,8 +2665,7 @@ "bowser": { "version": "2.11.0", "resolved": "https://registry.npmjs.org/bowser/-/bowser-2.11.0.tgz", - "integrity": "sha512-AlcaJBi/pqqJBIQ8U9Mcpc9i8Aqxn88Skv5d+xBX006BY5u8N3mGLHa5Lgppa7L/HfwgwLgZ6NYs+Ag6uUmJRA==", - "optional": true + "integrity": "sha512-AlcaJBi/pqqJBIQ8U9Mcpc9i8Aqxn88Skv5d+xBX006BY5u8N3mGLHa5Lgppa7L/HfwgwLgZ6NYs+Ag6uUmJRA==" }, "bson": { "version": "4.7.2", @@ -1082,15 +2714,6 @@ "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" }, - "fast-xml-parser": { - "version": "4.2.5", - "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.2.5.tgz", - "integrity": "sha512-B9/wizE4WngqQftFPmdaMYlXoJlJOYxGQOanC77fq9k8+Z0v5dDSVh+3glErdIROP//s/jgb7ZuxKfB8nVyo0g==", - "optional": true, - "requires": { - "strnum": "^1.0.5" - } - }, "file-uri-to-path": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", @@ -1435,8 +3058,7 @@ "strnum": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/strnum/-/strnum-1.0.5.tgz", - "integrity": "sha512-J8bbNyKKXl5qYcR36TIO8W3mVGVHrmmxsd5PAItGkmyzwJvybiw2IVq5nqd0i4LSNSkB/sx9VHllbfFdr9k1JA==", - "optional": true + "integrity": "sha512-J8bbNyKKXl5qYcR36TIO8W3mVGVHrmmxsd5PAItGkmyzwJvybiw2IVq5nqd0i4LSNSkB/sx9VHllbfFdr9k1JA==" }, "tr46": { "version": "3.0.0", @@ -1449,8 +3071,7 @@ "tslib": { "version": "2.6.2", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", - "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", - "optional": true + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==" }, "uWebSockets.js": { "version": "github:uNetworking/uWebSockets.js#7bf0faac5859fef2d113e83d22803f7833774c11", From 64e6ae6f6f4714f9c22632e05408aeef4aeb4b01 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 2 Aug 2024 02:09:55 +0000 Subject: [PATCH 051/204] Bump rexml from 3.3.1 to 3.3.3 in /frameworks/Ruby/rack Bumps [rexml](https://github.com/ruby/rexml) from 3.3.1 to 3.3.3. - [Release notes](https://github.com/ruby/rexml/releases) - [Changelog](https://github.com/ruby/rexml/blob/master/NEWS.md) - [Commits](https://github.com/ruby/rexml/compare/v3.3.1...v3.3.3) --- updated-dependencies: - dependency-name: rexml dependency-type: indirect ... Signed-off-by: dependabot[bot] --- frameworks/Ruby/rack/Gemfile.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frameworks/Ruby/rack/Gemfile.lock b/frameworks/Ruby/rack/Gemfile.lock index 0fa04f72580..7a08fdf7195 100644 --- a/frameworks/Ruby/rack/Gemfile.lock +++ b/frameworks/Ruby/rack/Gemfile.lock @@ -86,7 +86,7 @@ GEM rainbow (3.1.1) raindrops (0.20.1) regexp_parser (2.9.2) - rexml (3.3.1) + rexml (3.3.3) strscan rubocop (1.64.1) json (~> 2.3) From 912fb4827743ca029e8abb128eaf5f5ec1acb3c0 Mon Sep 17 00:00:00 2001 From: Rasmus Porsager Date: Fri, 2 Aug 2024 17:59:01 +0200 Subject: [PATCH 052/204] Add uwebsocketsjs (#9189) * Revert "Remove uwebsockets (#9160)" This reverts commit 4b0a91f07147386c8f11b36b1410f00b34c7611c. * Remove mysql * Don't fetch types on connect --- .../JavaScript/uwebsockets.js/README.md | 52 +++++ .../uwebsockets.js/benchmark_config.json | 47 +++++ .../uwebsockets.js/package-lock.json | 39 ++++ .../JavaScript/uwebsockets.js/package.json | 17 ++ .../uwebsockets.js/src/clustered.js | 23 +++ .../uwebsockets.js/src/database/postgres.js | 18 ++ .../JavaScript/uwebsockets.js/src/server.js | 194 ++++++++++++++++++ .../JavaScript/uwebsockets.js/src/utils.js | 86 ++++++++ .../uwebsockets.js-postgres.dockerfile | 12 ++ .../uwebsockets.js/uwebsockets.js.dockerfile | 11 + 10 files changed, 499 insertions(+) create mode 100644 frameworks/JavaScript/uwebsockets.js/README.md create mode 100644 frameworks/JavaScript/uwebsockets.js/benchmark_config.json create mode 100644 frameworks/JavaScript/uwebsockets.js/package-lock.json create mode 100644 frameworks/JavaScript/uwebsockets.js/package.json create mode 100644 frameworks/JavaScript/uwebsockets.js/src/clustered.js create mode 100644 frameworks/JavaScript/uwebsockets.js/src/database/postgres.js create mode 100644 frameworks/JavaScript/uwebsockets.js/src/server.js create mode 100644 frameworks/JavaScript/uwebsockets.js/src/utils.js create mode 100644 frameworks/JavaScript/uwebsockets.js/uwebsockets.js-postgres.dockerfile create mode 100644 frameworks/JavaScript/uwebsockets.js/uwebsockets.js.dockerfile diff --git a/frameworks/JavaScript/uwebsockets.js/README.md b/frameworks/JavaScript/uwebsockets.js/README.md new file mode 100644 index 00000000000..bc59e8c3026 --- /dev/null +++ b/frameworks/JavaScript/uwebsockets.js/README.md @@ -0,0 +1,52 @@ +# uWebSockets.js Benchmarking Test + +uWebSockets is a web server written in C/C++ (https://github.com/uNetworking/uWebSockets) + +µWebSockets.js is a web server bypass for Node.js (https://github.com/uNetworking/uWebSockets.js) + +## Important Libraries + +The tests were run with: + +- [uWebSockets.js](https://github.com/uNetworking/uWebSockets.js/) +- [postgres](https://github.com/porsager/postgres/) + +## Database + +There are individual handlers for each DB approach. The logic for each of them are found here: + +- [PostgreSQL](src/database/postgres.js) + +There are **no database endpoints** or drivers attached by default. + +To initialize the application with one of these, run any _one_ of the following commands: + +```sh +$ DATABASE=postgres npm start +``` + +## Test Endpoints + +> Visit the test requirements [here](https://github.com/TechEmpower/FrameworkBenchmarks/wiki/Project-Information-Framework-Tests-Overview) + +```sh +$ curl localhost:8080/json +$ curl localhost:8080/plaintext + +# The following are only available with the DATABASE env var + +$ curl localhost:8080/db +$ curl localhost:8080/fortunes + +$ curl localhost:8080/updates?queries= +$ curl localhost:8080/updates?queries=2 +$ curl localhost:8080/updates?queries=1000 +$ curl localhost:8080/updates?queries=foo +$ curl localhost:8080/updates?queries=0 + +$ curl localhost:8080/queries?queries= +$ curl localhost:8080/queries?queries=2 +$ curl localhost:8080/queries?queries=1000 +$ curl localhost:8080/queries?queries=foo +$ curl localhost:8080/queries?queries=0 +``` diff --git a/frameworks/JavaScript/uwebsockets.js/benchmark_config.json b/frameworks/JavaScript/uwebsockets.js/benchmark_config.json new file mode 100644 index 00000000000..a0ac515dcfe --- /dev/null +++ b/frameworks/JavaScript/uwebsockets.js/benchmark_config.json @@ -0,0 +1,47 @@ +{ + "framework": "uwebsockets.js", + "tests": [ + { + "default": { + "approach": "Realistic", + "classification": "Platform", + "database": "None", + "database_os": "Linux", + "display_name": "uWebSockets.js", + "flavor": "NodeJS", + "framework": "uWebSockets.js", + "json_url": "/json", + "language": "JavaScript", + "notes": "", + "orm": "Raw", + "os": "Linux", + "plaintext_url": "/plaintext", + "platform": "nodejs", + "port": 8080, + "versus": "nodejs", + "webserver": "None" + }, + "postgres": { + "approach": "Realistic", + "classification": "Platform", + "database": "Postgres", + "database_os": "Linux", + "db_url": "/db", + "display_name": "uWebSockets.js", + "flavor": "NodeJS", + "fortune_url": "/fortunes", + "framework": "uWebSockets.js", + "language": "JavaScript", + "notes": "", + "orm": "Raw", + "os": "Linux", + "platform": "None", + "port": 8080, + "query_url": "/queries?queries=", + "update_url": "/updates?queries=", + "versus": "nodejs", + "webserver": "None" + } + } + ] +} diff --git a/frameworks/JavaScript/uwebsockets.js/package-lock.json b/frameworks/JavaScript/uwebsockets.js/package-lock.json new file mode 100644 index 00000000000..13fff11e161 --- /dev/null +++ b/frameworks/JavaScript/uwebsockets.js/package-lock.json @@ -0,0 +1,39 @@ +{ + "name": "uwebsockets.js", + "version": "0.0.1", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "uwebsockets.js", + "version": "0.0.1", + "license": "MIT", + "dependencies": { + "postgres": "3.4.4", + "slow-json-stringify": "^2.0.1", + "uWebSockets.js": "uNetworking/uWebSockets.js#v20.44.0" + } + }, + "node_modules/postgres": { + "version": "3.4.4", + "resolved": "https://registry.npmjs.org/postgres/-/postgres-3.4.4.tgz", + "integrity": "sha512-IbyN+9KslkqcXa8AO9fxpk97PA4pzewvpi2B3Dwy9u4zpV32QicaEdgmF3eSQUzdRk7ttDHQejNgAEr4XoeH4A==", + "engines": { + "node": ">=12" + }, + "funding": { + "type": "individual", + "url": "https://github.com/sponsors/porsager" + } + }, + "node_modules/slow-json-stringify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/slow-json-stringify/-/slow-json-stringify-2.0.1.tgz", + "integrity": "sha512-jqyzIqTaSkRGcWdWqjmOLKHZgOGUT71ZCTsvQu1xGu9Mqaod7O26y5FJJEmaUQhaTWh0bkXv2qqN0i+EQsD1jQ==" + }, + "node_modules/uWebSockets.js": { + "version": "20.44.0", + "resolved": "git+ssh://git@github.com/uNetworking/uWebSockets.js.git#8fa05571bf6ea95be8966ad313d9d39453e381ae" + } + } +} diff --git a/frameworks/JavaScript/uwebsockets.js/package.json b/frameworks/JavaScript/uwebsockets.js/package.json new file mode 100644 index 00000000000..635c0a2b12a --- /dev/null +++ b/frameworks/JavaScript/uwebsockets.js/package.json @@ -0,0 +1,17 @@ +{ + "dependencies": { + "postgres": "3.4.4", + "slow-json-stringify": "^2.0.1", + "uWebSockets.js": "uNetworking/uWebSockets.js#v20.44.0" + }, + "license": "MIT", + "main": "src/server.js", + "name": "uwebsockets.js", + "private": true, + "scripts": { + "dev": "node src/server.js", + "start": "node src/clustered.js" + }, + "type": "module", + "version": "0.0.1" +} diff --git a/frameworks/JavaScript/uwebsockets.js/src/clustered.js b/frameworks/JavaScript/uwebsockets.js/src/clustered.js new file mode 100644 index 00000000000..95a57ec77f3 --- /dev/null +++ b/frameworks/JavaScript/uwebsockets.js/src/clustered.js @@ -0,0 +1,23 @@ +import cluster from "node:cluster"; +import os from "node:os"; +import process from "node:process"; + +if (cluster.isPrimary) { + // Master Node + console.log(`Primary ${process.pid} is running`); + + // Fork workers + const numCPUs = os.availableParallelism(); + for (let i = 0; i < numCPUs; i++) { + cluster.fork(); + } + + cluster.on("exit", (worker) => { + console.log(`worker ${worker.process.pid} died`); + process.exit(1); + }); +} else { + // Cluster Node + await import("./server.js"); + console.log(`Worker ${process.pid} started`); +} diff --git a/frameworks/JavaScript/uwebsockets.js/src/database/postgres.js b/frameworks/JavaScript/uwebsockets.js/src/database/postgres.js new file mode 100644 index 00000000000..db262a9757d --- /dev/null +++ b/frameworks/JavaScript/uwebsockets.js/src/database/postgres.js @@ -0,0 +1,18 @@ +import postgres from "postgres"; + +const sql = postgres({ + host: "tfb-database", + user: "benchmarkdbuser", + password: "benchmarkdbpass", + database: "hello_world", + fetch_types: false, + max: 1 +}); + +export const fortunes = async () => await sql`SELECT id, message FROM fortune`; + +export const find = async (id) => await sql`SELECT id, randomNumber FROM world WHERE id = ${id}`.then((arr) => arr[0]); + +export const bulkUpdate = async (worlds) => await sql`UPDATE world SET randomNumber = (update_data.randomNumber)::int + FROM (VALUES ${sql(worlds.map(world => [world.id, world.randomNumber]).sort((a, b) => (a[0] < b[0]) ? -1 : 1))}) AS update_data (id, randomNumber) + WHERE world.id = (update_data.id)::int`; diff --git a/frameworks/JavaScript/uwebsockets.js/src/server.js b/frameworks/JavaScript/uwebsockets.js/src/server.js new file mode 100644 index 00000000000..1db7d391f2a --- /dev/null +++ b/frameworks/JavaScript/uwebsockets.js/src/server.js @@ -0,0 +1,194 @@ +import uWebSockets from "uWebSockets.js"; +import { + addBenchmarkHeaders, + generateRandomNumber, + getQueriesCount, + handleError, + escape, + jsonSerializer, + worldObjectSerializer, + sortByMessage +} from "./utils.js"; + +let db; +const { DATABASE } = process.env; +if (DATABASE) db = await import(`./database/${DATABASE}.js`); + +const webserver = uWebSockets.App(); + +webserver.get("/plaintext", new uWebSockets.DeclarativeResponse() + .writeHeader("Server", "uWebSockets.js") + .writeHeader("Content-Type", "text/plain") + .end("Hello, World!") +); + +webserver.get("/json", (response) => { + addBenchmarkHeaders(response); + response.writeHeader("Content-Type", "application/json"); + // response.end(JSON.stringify({ message: "Hello, World!" })); + response.end(jsonSerializer({ message: "Hello, World!" })); +}); + +if (db) { + webserver.get("/db", async (response) => { + response.onAborted(() => { + response.aborted = true; + }); + + try { + const row = await db.find(generateRandomNumber()); + + if (response.aborted) { + return; + } + + response.cork(() => { + addBenchmarkHeaders(response); + response.writeHeader("Content-Type", "application/json"); + // response.end(JSON.stringify(rows)); + response.end(worldObjectSerializer(row)); + }); + } catch (error) { + if (response.aborted) { + return; + } + + handleError(error, response); + } + }); + + webserver.get("/queries", async (response, request) => { + response.onAborted(() => { + response.aborted = true; + }); + + try { + const queriesCount = getQueriesCount(request); + + const databaseJobs = new Array(queriesCount); + + for (let i = 0; i < queriesCount; i++) { + databaseJobs[i] = db.find(generateRandomNumber()); + } + + const worldObjects = await Promise.all(databaseJobs); + + if (response.aborted) { + return; + } + + response.cork(() => { + addBenchmarkHeaders(response); + response.writeHeader("Content-Type", "application/json"); + response.end(JSON.stringify(worldObjects)); + }); + } catch (error) { + if (response.aborted) { + return; + } + + handleError(error, response); + } + }); + + const extra = { id: 0, message: "Additional fortune added at request time." }; + + webserver.get("/fortunes", async (response) => { + response.onAborted(() => { + response.aborted = true; + }); + + try { + const rows = [extra, ...await db.fortunes()]; + + if (response.aborted) { + return; + } + + // rows.push({ + // id: 0, + // message: "Additional fortune added at request time.", + // }); + + // rows.sort((a, b) => (a.message < b.message) ? -1 : 1); + sortByMessage(rows) + + const n = rows.length + + let html = "", i = 0; + for (; i < n; i++) { + html += `${rows[i].id}${escape(rows[i].message)}`; + } + + response.cork(() => { + addBenchmarkHeaders(response); + response.writeHeader("Content-Type", "text/html; charset=utf-8"); + response.end(`Fortunes${html}
idmessage
`); + }); + } catch (error) { + if (response.aborted) { + return; + } + + handleError(error, response); + } + }); + + webserver.get("/updates", async (response, request) => { + response.onAborted(() => { + response.aborted = true; + }); + + try { + const queriesCount = getQueriesCount(request); + + const databaseJobs = new Array(queriesCount); + + for (let i = 0; i < queriesCount; i++) { + databaseJobs[i] = db.find(generateRandomNumber()); + } + + const worldObjects = await Promise.all(databaseJobs); + + for (let i = 0; i < queriesCount; i++) { + worldObjects[i].randomNumber = generateRandomNumber(); + } + + await db.bulkUpdate(worldObjects); + + if (response.aborted) { + return; + } + + response.cork(() => { + addBenchmarkHeaders(response); + response.writeHeader("Content-Type", "application/json"); + response.end(JSON.stringify(worldObjects)); + }); + } catch (error) { + if (response.aborted) { + return; + } + + handleError(error, response); + } + }); +} + +webserver.any("/*", (response) => { + response.writeStatus("404 Not Found"); + addBenchmarkHeaders(response); + response.writeHeader("Content-Type", "text/plain"); + response.end("Not Found"); +}); + +const host = process.env.HOST || "0.0.0.0"; +const port = parseInt(process.env.PORT || "8080"); +webserver.listen(host, port, (socket) => { + if (!socket) { + console.error(`Couldn't bind to http://${host}:${port}!`); + process.exit(1); + } + + console.log(`Successfully bound to http://${host}:${port}.`); +}); diff --git a/frameworks/JavaScript/uwebsockets.js/src/utils.js b/frameworks/JavaScript/uwebsockets.js/src/utils.js new file mode 100644 index 00000000000..b3d46e7e11c --- /dev/null +++ b/frameworks/JavaScript/uwebsockets.js/src/utils.js @@ -0,0 +1,86 @@ +import { sjs, attr } from 'slow-json-stringify' + +/** + * Add Benchmark HTTP response headers. + * + * Add HTTP response headers `Server` which is required by the test suite. + * Header `Date` is automatically added by uWebsockets + * https://github.com/uNetworking/uWebSockets/blob/master/src/HttpResponse.h#L78 + * + * https://github.com/TechEmpower/FrameworkBenchmarks/wiki/Project-Information-Framework-Tests-Overview + * + * @param {import('uWebSockets.js').HttpResponse} response + */ +export function addBenchmarkHeaders(response) { + response.writeHeader("Server", "uWebSockets.js"); +} + +/** + * Handle error for response + * + * @param {Error} error + * @param {import('uWebSockets.js').HttpResponse} response + */ +export function handleError(error, response) { + console.error(error); + response.cork(() => { + addBenchmarkHeaders(response); + response.writeHeader("Content-Type", "text/plain"); + response.end("Internal Server Error"); + }); +} + +/** + * Get queries count + * + * @param {import('uWebSockets.js').HttpRequest} request + */ +export function getQueriesCount(request) { + return Math.min(parseInt(request.getQuery("queries")) || 1, 500); +} + +/** + * Generate random number + * + */ +export function generateRandomNumber() { + return Math.ceil(Math.random() * 10000); +} + +/** + * Escape unsafe HTML Code + * + */ +const escapeHTMLRules = { '&': '&', '<': '<', '>': '>', '"': '"', "'": ''', '/': '/' } + +const unsafeHTMLMatcher = /[&<>"'\/]/g + +export function escape(text) { + if (unsafeHTMLMatcher.test(text) === false) return text; + return text.replace(unsafeHTMLMatcher, function (m) { return escapeHTMLRules[m] || m; }); +} + +/** + * Using Slow json stringify module to get faster results + */ +export const jsonSerializer = sjs({ message: attr("string")}); +export const worldObjectSerializer = sjs({ id: attr('number'), randomnumber: attr('number') }); +// export const worldObjectsSerializer = sjs({ rows: attr("array", worldObjectSerializer) }); + +/** + * Using Sort method which is performant for the test scenario + * @returns + */ +export function sortByMessage (arr) { + const n = arr.length + for (let i = 1; i < n; i++) { + const c = arr[i] + let j = i - 1 + while ((j > -1) && (c.message < arr[j].message)) { + arr[j + 1] = arr[j] + j-- + } + arr[j + 1] = c + } + return arr +} \ No newline at end of file diff --git a/frameworks/JavaScript/uwebsockets.js/uwebsockets.js-postgres.dockerfile b/frameworks/JavaScript/uwebsockets.js/uwebsockets.js-postgres.dockerfile new file mode 100644 index 00000000000..ba7d0eee5f6 --- /dev/null +++ b/frameworks/JavaScript/uwebsockets.js/uwebsockets.js-postgres.dockerfile @@ -0,0 +1,12 @@ +FROM node:20-slim + +COPY ./ ./ + +RUN npm install + +ENV NODE_ENV production +ENV DATABASE postgres + +EXPOSE 8080 + +CMD ["npm", "start"] diff --git a/frameworks/JavaScript/uwebsockets.js/uwebsockets.js.dockerfile b/frameworks/JavaScript/uwebsockets.js/uwebsockets.js.dockerfile new file mode 100644 index 00000000000..4262ad19953 --- /dev/null +++ b/frameworks/JavaScript/uwebsockets.js/uwebsockets.js.dockerfile @@ -0,0 +1,11 @@ +FROM node:20-slim + +COPY ./ ./ + +RUN npm install + +ENV NODE_ENV production + +EXPOSE 8080 + +CMD ["npm", "start"] From f496311ba17a4725432703059c0d58317f5b651e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gyula=20Bibern=C3=A1th?= <27079815+b-gyula@users.noreply.github.com> Date: Fri, 2 Aug 2024 17:59:22 +0200 Subject: [PATCH 053/204] Java/armeria: /fortunes exposed to test (#9179) Scala/vertx-web-scala-postgres: /json endpoint exposed to test (makes them appear in composite scoring also) --- frameworks/Java/armeria/benchmark_config.json | 1 + .../vertx-web-scala/benchmark_config.json | 1 + .../src/main/scala/vertx/App.scala | 30 ++++++++----------- 3 files changed, 15 insertions(+), 17 deletions(-) diff --git a/frameworks/Java/armeria/benchmark_config.json b/frameworks/Java/armeria/benchmark_config.json index 32cdbd6303f..bdc474dfd9b 100644 --- a/frameworks/Java/armeria/benchmark_config.json +++ b/frameworks/Java/armeria/benchmark_config.json @@ -7,6 +7,7 @@ "db_url": "/db", "query_url": "/queries/", "update_url": "/updates/", + "fortune_url": "/fortunes", "port": 8080, "approach": "Realistic", "classification": "Micro", diff --git a/frameworks/Scala/vertx-web-scala/benchmark_config.json b/frameworks/Scala/vertx-web-scala/benchmark_config.json index d5f73751a49..4a8c4242d34 100755 --- a/frameworks/Scala/vertx-web-scala/benchmark_config.json +++ b/frameworks/Scala/vertx-web-scala/benchmark_config.json @@ -8,6 +8,7 @@ "fortune_url": "/fortunes", "update_url": "/updates?queries=", "plaintext_url": "/plaintext", + "json_url": "/json", "port": 8080, "approach": "Realistic", "classification": "Micro", diff --git a/frameworks/Scala/vertx-web-scala/src/main/scala/vertx/App.scala b/frameworks/Scala/vertx-web-scala/src/main/scala/vertx/App.scala index 469ba0512d6..0f2991c3b47 100644 --- a/frameworks/Scala/vertx-web-scala/src/main/scala/vertx/App.scala +++ b/frameworks/Scala/vertx-web-scala/src/main/scala/vertx/App.scala @@ -26,7 +26,7 @@ import scala.util.{Failure, Sorting, Success, Try} case class Header(name: CharSequence, value: String) class App extends ScalaVerticle { - + import App._ private val HELLO_WORLD = "Hello, world!" private val HELLO_WORLD_BUFFER = Buffer.buffer(HELLO_WORLD, "UTF-8") private val SERVER = "vert.x" @@ -116,8 +116,7 @@ class App extends ScalaVerticle { .end(World(row.getInteger(0), row.getInteger(1)).encode()) } } else { - App.logger.error("Failed to handle request", ar.cause()) - request.response.setStatusCode(500).end(ar.cause.getMessage) + sendError(request, ar.cause, "Failed to handle Db request") } } ) @@ -136,7 +135,7 @@ class App extends ScalaVerticle { if (!failed) { if (ar.failed) { failed = true - request.response.setStatusCode(500).end(ar.cause.getMessage) + sendError(request, ar.cause, "Failed to handle Queries request") return } // we need a final reference @@ -155,11 +154,6 @@ class App extends ScalaVerticle { } private def handleUpdates(request: HttpServerRequest): Unit = { - def sendError(err: Throwable): Unit = { - App.logger.error("", err) - request.response.setStatusCode(500).end(err.getMessage) - } - def handleUpdates(conn: SqlConnection, worlds: Array[World]): Unit = { Sorting.quickSort(worlds) @@ -170,7 +164,7 @@ class App extends ScalaVerticle { batch, (ar: AsyncResult[RowSet[Row]]) => { if (ar.failed) { - sendError(ar.cause) + sendError(request, ar.cause, "handleUpdates: failed to update DB") return } @@ -197,7 +191,7 @@ class App extends ScalaVerticle { if (!failed) { if (ar2.failed) { failed = true - sendError(ar2.cause) + sendError(request, ar2.cause, "handleUpdates: failed to read DB") return } worlds(index) = World(ar2.result.iterator.next.getInteger(0), App.randomWorld()) @@ -206,7 +200,6 @@ class App extends ScalaVerticle { } } ) - i += 1 } } @@ -230,9 +223,7 @@ class App extends ScalaVerticle { responseWithHeaders(request.response, contentTypeHtml) .end(html.fortune(fortunes).body) } else { - val err = ar.cause - App.logger.error("", err) - response.setStatusCode(500).end(err.getMessage) + sendError(request, ar.cause, "handleFortunes failed to update DB") } } ) @@ -241,9 +232,9 @@ class App extends ScalaVerticle { object App { val logger: Logger = Logger[App] - + val defaultConfigPath = "src/main/conf/config.json" def main(args: Array[String]): Unit = { - val config = new JsonObject(Files.readString(new File(args(0)).toPath)) + val config = new JsonObject(Files.readString(new File(if(args.length < 1) defaultConfigPath else args(0)).toPath)) val vertx = Vertx.vertx(VertxOptions().setPreferNativeTransport(true)) printConfig(vertx) @@ -299,4 +290,9 @@ object App { logger.info("Event Loop Size: {}", JVertxOptions.DEFAULT_EVENT_LOOP_POOL_SIZE) logger.info("Native transport: {}", vertx.isNativeTransportEnabled) } + + def sendError(request: HttpServerRequest, err: Throwable, msg: String = ""): Unit = { + App.logger.error(msg, err) + request.response.setStatusCode(500).end(err.getMessage) + } } From dbaaefa53c929c51cd571cd923c49c2b47213968 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Deleuze?= Date: Fri, 2 Aug 2024 17:59:44 +0200 Subject: [PATCH 054/204] Cleanup and upgrade of the Spring implementations to Spring Boot 3.3 (#9167) * Upgrade spring test to Spring Boot 3.3.1 This commit also introduces several refinements: - Upgrade to Java 21 with Liberica JRE - Make Message a top level class - Properly exclude autoconfigurations based on profiles - Use Spring Boot 3.3 executable JAR unpack feature - Remove java options enabled by default - Keep debug symbol in JVM bytecode for parameter name resolution * Upgrade spring-webflux test to Spring Boot 3.3.1 This commit also introduces several refinements - Reactivate the test - Remove unmaintained variants to keep only r2dbc and mongo - Upgrade to Spring Boot 3.3.1 - Upgrade to Java 21 with Liberica JRE - Dependency cleanup - Various related updates - Add JSON and textplain endpoints - Properly exclude autoconfigurations based on profiles - Use Spring Boot 3.3 executable JAR unpack feature - Add -Dreactor.netty.http.server.lastFlushWhenNoRead=true property - Keep debug symbol in JVM bytecode for parameter name resolution --- frameworks/Java/spring-webflux/README.md | 9 -- .../Java/spring-webflux/benchmark_config.json | 67 +------------ frameworks/Java/spring-webflux/config.toml | 45 --------- frameworks/Java/spring-webflux/pom.xml | 50 ++-------- .../spring-webflux-jdbc.dockerfile | 13 --- .../spring-webflux-mongo.dockerfile | 9 +- .../spring-webflux-pgclient.dockerfile | 13 --- .../spring-webflux-rxjdbc.dockerfile | 13 --- .../spring-webflux/spring-webflux.dockerfile | 8 +- .../src/main/java/benchmark/App.java | 39 +------- .../src/main/java/benchmark/DateHandler.java | 19 ---- .../src/main/java/benchmark/PgClients.java | 19 ---- .../src/main/java/benchmark/ServerFilter.java | 21 ++++- .../java/benchmark/config/JdbcConfig.java | 22 ----- .../java/benchmark/config/PgClientConfig.java | 94 ------------------- .../java/benchmark/config/R2dbcConfig.java | 63 ------------- .../benchmark/config/ReactiveMongoConfig.java | 54 ----------- .../java/benchmark/config/RxJdbcConfig.java | 25 ----- .../main/java/benchmark/model/Message.java | 15 +++ .../repository/MongoDbRepository.java | 17 ++-- .../repository/PgClientDbRepository.java | 79 ---------------- .../repository/R2dbcDbRepository.java | 4 +- .../repository/RxJdbcDbRepository.java | 60 ------------ .../java/benchmark/web/WebfluxHandler.java | 23 +++-- .../java/benchmark/web/WebfluxRouter.java | 32 ++----- .../src/main/resources/application.yml | 63 ++----------- frameworks/Java/spring/pom.xml | 7 +- frameworks/Java/spring/spring-jpa.dockerfile | 10 +- .../Java/spring/spring-mongo.dockerfile | 10 +- frameworks/Java/spring/spring.dockerfile | 10 +- .../Java/spring/src/main/java/hello/App.java | 2 +- .../hello/controller/HelloController.java | 15 +-- .../src/main/java/hello/model/Message.java | 15 +++ .../spring/src/main/resources/application.yml | 17 +++- 34 files changed, 148 insertions(+), 814 deletions(-) delete mode 100644 frameworks/Java/spring-webflux/spring-webflux-jdbc.dockerfile delete mode 100644 frameworks/Java/spring-webflux/spring-webflux-pgclient.dockerfile delete mode 100644 frameworks/Java/spring-webflux/spring-webflux-rxjdbc.dockerfile mode change 100755 => 100644 frameworks/Java/spring-webflux/src/main/java/benchmark/App.java delete mode 100644 frameworks/Java/spring-webflux/src/main/java/benchmark/DateHandler.java delete mode 100644 frameworks/Java/spring-webflux/src/main/java/benchmark/PgClients.java delete mode 100644 frameworks/Java/spring-webflux/src/main/java/benchmark/config/JdbcConfig.java delete mode 100644 frameworks/Java/spring-webflux/src/main/java/benchmark/config/PgClientConfig.java delete mode 100644 frameworks/Java/spring-webflux/src/main/java/benchmark/config/R2dbcConfig.java delete mode 100644 frameworks/Java/spring-webflux/src/main/java/benchmark/config/ReactiveMongoConfig.java delete mode 100644 frameworks/Java/spring-webflux/src/main/java/benchmark/config/RxJdbcConfig.java create mode 100644 frameworks/Java/spring-webflux/src/main/java/benchmark/model/Message.java delete mode 100644 frameworks/Java/spring-webflux/src/main/java/benchmark/repository/PgClientDbRepository.java delete mode 100644 frameworks/Java/spring-webflux/src/main/java/benchmark/repository/RxJdbcDbRepository.java create mode 100644 frameworks/Java/spring/src/main/java/hello/model/Message.java diff --git a/frameworks/Java/spring-webflux/README.md b/frameworks/Java/spring-webflux/README.md index 91e18bc9ceb..74297391137 100755 --- a/frameworks/Java/spring-webflux/README.md +++ b/frameworks/Java/spring-webflux/README.md @@ -37,15 +37,6 @@ For mongoDB access, spring-data-mongodb with reactive support is used. See [Mong * [Template rendering test source](src/main/java/benchmark/web/WebfluxRouter.java) -## Versions - -* [Java OpenJDK 10](http://openjdk.java.net/) -* [Spring boot 2.1.0.RELEASE](https://spring.io/projects/spring-boot) -* [Spring data mongodb 2.1.0.RELEASE](https://projects.spring.io/spring-data-mongodb/) -* [reactive-pg-client 0.10.6](https://github.com/reactiverse/reactive-pg-client) -* [rxjava2-jdbc 0.2.0](https://github.com/davidmoten/rxjava2-jdbc) -* [r2dbc-postgresql 1.0.0.BUILD-SNAPSHOT](https://github.com/r2dbc/r2dbc-postgresql) - ## Test URLs ### Plaintext Test diff --git a/frameworks/Java/spring-webflux/benchmark_config.json b/frameworks/Java/spring-webflux/benchmark_config.json index 396e9e22a1c..d3d0746d448 100644 --- a/frameworks/Java/spring-webflux/benchmark_config.json +++ b/frameworks/Java/spring-webflux/benchmark_config.json @@ -2,9 +2,11 @@ "framework": "spring-webflux", "tests": [{ "default": { + "json_url": "/json", "db_url": "/db", "query_url": "/queries?queries=", "fortune_url": "/fortunes", + "plaintext_url": "/plaintext", "update_url": "/updates?queries=", "port": 8080, "approach": "Realistic", @@ -23,9 +25,11 @@ "versus": "spring" }, "mongo": { + "json_url": "/json", "db_url": "/db", "query_url": "/queries?queries=", "fortune_url": "/fortunes", + "plaintext_url": "/plaintext", "port": 8080, "approach": "Realistic", "classification": "Fullstack", @@ -41,69 +45,6 @@ "display_name": "spring-webflux-mongo", "notes": "", "versus": "spring" - }, - "pgclient": { - "db_url": "/db", - "query_url": "/queries?queries=", - "fortune_url": "/fortunes", - "update_url": "/updates?queries=", - "port": 8080, - "approach": "Realistic", - "classification": "Fullstack", - "database": "Postgres", - "framework": "spring", - "language": "Java", - "flavor": "None", - "orm": "Micro", - "platform": "Netty", - "webserver": "None", - "os": "Linux", - "database_os": "Linux", - "display_name": "spring-webflux-pgclient", - "notes": "", - "versus": "spring" - }, - "rxjdbc": { - "db_url": "/db", - "query_url": "/queries?queries=", - "fortune_url": "/fortunes", - "update_url": "/updates?queries=", - "port": 8080, - "approach": "Realistic", - "classification": "Fullstack", - "database": "Postgres", - "framework": "spring", - "language": "Java", - "flavor": "None", - "orm": "Micro", - "platform": "Netty", - "webserver": "None", - "os": "Linux", - "database_os": "Linux", - "display_name": "spring-webflux-rxjdbc", - "notes": "", - "versus": "spring" - }, - "jdbc": { - "db_url": "/db", - "query_url": "/queries?queries=", - "fortune_url": "/fortunes", - "update_url": "/updates?queries=", - "port": 8080, - "approach": "Realistic", - "classification": "Fullstack", - "database": "Postgres", - "framework": "spring", - "language": "Java", - "flavor": "None", - "orm": "Micro", - "platform": "Netty", - "webserver": "None", - "os": "Linux", - "database_os": "Linux", - "display_name": "spring-webflux-jdbc", - "notes": "", - "versus": "spring" } }] } diff --git a/frameworks/Java/spring-webflux/config.toml b/frameworks/Java/spring-webflux/config.toml index 0cf76705159..806591a8384 100644 --- a/frameworks/Java/spring-webflux/config.toml +++ b/frameworks/Java/spring-webflux/config.toml @@ -16,36 +16,6 @@ platform = "Netty" webserver = "None" versus = "spring" -[pgclient] -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 = "Micro" -platform = "Netty" -webserver = "None" -versus = "spring" - -[jdbc] -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 = "Micro" -platform = "Netty" -webserver = "None" -versus = "spring" - [mongo] urls.db = "/db" urls.query = "/queries?queries=" @@ -59,18 +29,3 @@ orm = "Full" platform = "Netty" webserver = "None" versus = "spring" - -[rxjdbc] -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 = "Micro" -platform = "Netty" -webserver = "None" -versus = "spring" diff --git a/frameworks/Java/spring-webflux/pom.xml b/frameworks/Java/spring-webflux/pom.xml index bec59f53b95..4dd5b09698c 100644 --- a/frameworks/Java/spring-webflux/pom.xml +++ b/frameworks/Java/spring-webflux/pom.xml @@ -8,19 +8,18 @@ benchmark spring-webflux-benchmark - 1.1-SNAPSHOT + 1.0-SNAPSHOT org.springframework.boot spring-boot-starter-parent - 3.3.0 + 3.3.1 - 17 + 21 + 21 UTF-8 - 0.11.4 - 0.2.14 @@ -30,7 +29,11 @@ org.springframework.boot - spring-boot-starter-jdbc + spring-boot-starter-data-r2dbc + + + org.postgresql + r2dbc-postgresql org.springframework.boot @@ -40,38 +43,6 @@ org.springframework.boot spring-boot-starter-data-mongodb-reactive - - org.postgresql - postgresql - - - io.reactiverse - reactive-pg-client - ${pgclient.version} - - - com.github.davidmoten - rxjava2-jdbc - ${rxjava2-jdbc.version} - - - - org.postgresql - r2dbc-postgresql - - - io.r2dbc - r2dbc-pool - - - org.springframework.data - spring-data-r2dbc - - - org.springframework.boot - spring-boot-configuration-processor - true - @@ -84,9 +55,6 @@ org.apache.maven.plugins maven-compiler-plugin - - false - diff --git a/frameworks/Java/spring-webflux/spring-webflux-jdbc.dockerfile b/frameworks/Java/spring-webflux/spring-webflux-jdbc.dockerfile deleted file mode 100644 index 7c1daea95f3..00000000000 --- a/frameworks/Java/spring-webflux/spring-webflux-jdbc.dockerfile +++ /dev/null @@ -1,13 +0,0 @@ -FROM maven:3.9.6-eclipse-temurin-21 as maven -WORKDIR /spring -COPY src src -COPY pom.xml pom.xml -RUN mvn package -q - -FROM eclipse-temurin:21.0.3_9-jre-jammy -WORKDIR /spring -COPY --from=maven /spring/target/spring-webflux-benchmark.jar app.jar - -EXPOSE 8080 - -CMD ["java", "-server", "-XX:+UseNUMA", "-Dlogging.level.root=OFF", "-jar", "app.jar", "--spring.profiles.active=jdbc,postgres"] diff --git a/frameworks/Java/spring-webflux/spring-webflux-mongo.dockerfile b/frameworks/Java/spring-webflux/spring-webflux-mongo.dockerfile index d26a7bda983..41eedefa4c6 100644 --- a/frameworks/Java/spring-webflux/spring-webflux-mongo.dockerfile +++ b/frameworks/Java/spring-webflux/spring-webflux-mongo.dockerfile @@ -1,13 +1,16 @@ -FROM maven:3.9.6-eclipse-temurin-21 as maven +FROM maven:3.9.5-eclipse-temurin-21 as maven WORKDIR /spring COPY src src COPY pom.xml pom.xml RUN mvn package -q -FROM eclipse-temurin:21.0.3_9-jre-jammy +FROM bellsoft/liberica-openjre-debian:21 WORKDIR /spring COPY --from=maven /spring/target/spring-webflux-benchmark.jar app.jar +# See https://docs.spring.io/spring-boot/reference/packaging/efficient.html +RUN java -Djarmode=tools -jar app.jar extract + EXPOSE 8080 -CMD ["java", "-server", "-XX:+UseNUMA", "-Dlogging.level.root=OFF", "-jar", "app.jar", "--spring.profiles.active=mongo"] +CMD ["java", "-Dlogging.level.root=OFF", "-Dreactor.netty.http.server.lastFlushWhenNoRead=true", "-jar", "app/app.jar", "--spring.profiles.active=mongo"] \ No newline at end of file diff --git a/frameworks/Java/spring-webflux/spring-webflux-pgclient.dockerfile b/frameworks/Java/spring-webflux/spring-webflux-pgclient.dockerfile deleted file mode 100644 index 2bf38ec11e0..00000000000 --- a/frameworks/Java/spring-webflux/spring-webflux-pgclient.dockerfile +++ /dev/null @@ -1,13 +0,0 @@ -FROM maven:3.9.6-eclipse-temurin-21 as maven -WORKDIR /spring -COPY src src -COPY pom.xml pom.xml -RUN mvn package -q - -FROM eclipse-temurin:21.0.3_9-jre-jammy -WORKDIR /spring -COPY --from=maven /spring/target/spring-webflux-benchmark.jar app.jar - -EXPOSE 8080 - -CMD ["java", "-server", "-XX:+UseNUMA", "-Dlogging.level.root=OFF", "-jar", "app.jar", "--spring.profiles.active=pgclient,postgres"] diff --git a/frameworks/Java/spring-webflux/spring-webflux-rxjdbc.dockerfile b/frameworks/Java/spring-webflux/spring-webflux-rxjdbc.dockerfile deleted file mode 100644 index 0e1edfb74a9..00000000000 --- a/frameworks/Java/spring-webflux/spring-webflux-rxjdbc.dockerfile +++ /dev/null @@ -1,13 +0,0 @@ -FROM maven:3.9.6-eclipse-temurin-21 as maven -WORKDIR /spring -COPY src src -COPY pom.xml pom.xml -RUN mvn package -q - -FROM eclipse-temurin:21.0.3_9-jre-jammy -WORKDIR /spring -COPY --from=maven /spring/target/spring-webflux-benchmark.jar app.jar - -EXPOSE 8080 - -CMD ["java", "-server", "-XX:+UseNUMA", "-Dlogging.level.root=OFF", "-jar", "app.jar", "--spring.profiles.active=rxjdbc,postgres"] diff --git a/frameworks/Java/spring-webflux/spring-webflux.dockerfile b/frameworks/Java/spring-webflux/spring-webflux.dockerfile index 504fb71cfae..6ff2ed4e537 100644 --- a/frameworks/Java/spring-webflux/spring-webflux.dockerfile +++ b/frameworks/Java/spring-webflux/spring-webflux.dockerfile @@ -1,13 +1,15 @@ -FROM maven:3.9.6-eclipse-temurin-21 as maven +FROM maven:3.9.5-eclipse-temurin-21 as maven WORKDIR /spring COPY src src COPY pom.xml pom.xml RUN mvn package -q -FROM eclipse-temurin:21.0.3_9-jre-jammy +FROM bellsoft/liberica-openjre-debian:21 WORKDIR /spring COPY --from=maven /spring/target/spring-webflux-benchmark.jar app.jar +# See https://docs.spring.io/spring-boot/reference/packaging/efficient.html +RUN java -Djarmode=tools -jar app.jar extract EXPOSE 8080 -CMD ["java", "-server", "-XX:+UseNUMA", "-Dlogging.level.root=OFF", "-jar", "app.jar", "--spring.profiles.active=r2dbc,postgres"] +CMD ["java", "-Dlogging.level.root=OFF", "-Dreactor.netty.http.server.lastFlushWhenNoRead=true", "-jar", "app/app.jar", "--spring.profiles.active=r2dbc"] diff --git a/frameworks/Java/spring-webflux/src/main/java/benchmark/App.java b/frameworks/Java/spring-webflux/src/main/java/benchmark/App.java old mode 100755 new mode 100644 index 9fa3f318361..37ff0a80ff0 --- a/frameworks/Java/spring-webflux/src/main/java/benchmark/App.java +++ b/frameworks/Java/spring-webflux/src/main/java/benchmark/App.java @@ -1,52 +1,15 @@ package benchmark; -import java.util.concurrent.Executors; - -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.boot.context.properties.EnableConfigurationProperties; -import org.springframework.boot.web.reactive.result.view.MustacheViewResolver; -import org.springframework.context.annotation.Bean; import org.springframework.scheduling.annotation.EnableScheduling; -import org.springframework.web.reactive.config.EnableWebFlux; -import org.springframework.web.reactive.config.ViewResolverRegistry; -import org.springframework.web.reactive.config.WebFluxConfigurer; - -import reactor.core.scheduler.Scheduler; -import reactor.core.scheduler.Schedulers; @SpringBootApplication -@EnableWebFlux @EnableScheduling -@EnableConfigurationProperties -public class App implements WebFluxConfigurer { - - @Autowired - private MustacheViewResolver mustacheViewResolver; +public class App { public static void main(String[] args) { SpringApplication.run(App.class, args); } - @Bean - ServerFilter serverFilter() { - return new ServerFilter(); - } - - @Bean - DateHandler dateHandler() { - return new DateHandler(); - } - - @Bean - Scheduler ioScheduler() { - return Schedulers.fromExecutor(Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors() * 2)); - } - - @Override - public void configureViewResolvers(ViewResolverRegistry registry) { - registry.viewResolver(mustacheViewResolver); - } - } \ No newline at end of file diff --git a/frameworks/Java/spring-webflux/src/main/java/benchmark/DateHandler.java b/frameworks/Java/spring-webflux/src/main/java/benchmark/DateHandler.java deleted file mode 100644 index fdaab4a2209..00000000000 --- a/frameworks/Java/spring-webflux/src/main/java/benchmark/DateHandler.java +++ /dev/null @@ -1,19 +0,0 @@ -package benchmark; - -import org.springframework.scheduling.annotation.Scheduled; - -import java.util.Date; - -public class DateHandler { - - private Date date = new Date(); - - @Scheduled(fixedRate = 1000) - public void update() { - this.date = new Date(); - } - - public Date getDate() { - return date; - } -} diff --git a/frameworks/Java/spring-webflux/src/main/java/benchmark/PgClients.java b/frameworks/Java/spring-webflux/src/main/java/benchmark/PgClients.java deleted file mode 100644 index 902478447c6..00000000000 --- a/frameworks/Java/spring-webflux/src/main/java/benchmark/PgClients.java +++ /dev/null @@ -1,19 +0,0 @@ -package benchmark; - -import io.reactiverse.pgclient.PgClient; - -import java.util.Collection; -import java.util.Iterator; -import java.util.stream.Stream; - -public class PgClients { - private final Iterator iterator; - - public PgClients(Collection clients) { - iterator = Stream.generate(() -> clients).flatMap(Collection::stream).iterator(); - } - - public synchronized PgClient getOne() { - return iterator.next(); - } -} \ No newline at end of file diff --git a/frameworks/Java/spring-webflux/src/main/java/benchmark/ServerFilter.java b/frameworks/Java/spring-webflux/src/main/java/benchmark/ServerFilter.java index 40cc32ff9a7..685ac39e6ad 100644 --- a/frameworks/Java/spring-webflux/src/main/java/benchmark/ServerFilter.java +++ b/frameworks/Java/spring-webflux/src/main/java/benchmark/ServerFilter.java @@ -1,20 +1,35 @@ -package benchmark; +package benchmark.web; import io.netty.handler.codec.http.HttpHeaderNames; import org.springframework.http.HttpHeaders; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; import org.springframework.web.server.ServerWebExchange; import org.springframework.web.server.WebFilter; import org.springframework.web.server.WebFilterChain; import reactor.core.publisher.Mono; +@Component public class ServerFilter implements WebFilter { + private static final String SERVER_NAME = "spring-webflux"; + private String date; + + public ServerFilter() { + updateDate(); + } + + @Scheduled(fixedRate = 1000) + public void updateDate() { + this.date = java.time.format.DateTimeFormatter.RFC_1123_DATE_TIME.format(java.time.ZonedDateTime.now()); + } + @Override public Mono filter(ServerWebExchange exchange, WebFilterChain chain) { HttpHeaders headers = exchange.getResponse().getHeaders(); headers.add(HttpHeaderNames.SERVER.toString(), SERVER_NAME); - headers.add(HttpHeaderNames.DATE.toString(), java.time.format.DateTimeFormatter.RFC_1123_DATE_TIME.format(java.time.ZonedDateTime.now())); + headers.add(HttpHeaderNames.DATE.toString(), this.date); return chain.filter(exchange); } -} +} \ No newline at end of file diff --git a/frameworks/Java/spring-webflux/src/main/java/benchmark/config/JdbcConfig.java b/frameworks/Java/spring-webflux/src/main/java/benchmark/config/JdbcConfig.java deleted file mode 100644 index d99729490a4..00000000000 --- a/frameworks/Java/spring-webflux/src/main/java/benchmark/config/JdbcConfig.java +++ /dev/null @@ -1,22 +0,0 @@ -package benchmark.config; - -import com.zaxxer.hikari.HikariDataSource; -import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.Profile; - -import javax.sql.DataSource; - -@Configuration -@Profile("jdbc") -public class JdbcConfig { - - @Bean - DataSource datasource(DataSourceProperties dataSourceProperties) { - HikariDataSource dataSource = dataSourceProperties.initializeDataSourceBuilder().type(HikariDataSource.class).build(); - dataSource.setMaximumPoolSize(Runtime.getRuntime().availableProcessors() * 2); - - return dataSource; - } -} \ No newline at end of file diff --git a/frameworks/Java/spring-webflux/src/main/java/benchmark/config/PgClientConfig.java b/frameworks/Java/spring-webflux/src/main/java/benchmark/config/PgClientConfig.java deleted file mode 100644 index 9ebf6db60c9..00000000000 --- a/frameworks/Java/spring-webflux/src/main/java/benchmark/config/PgClientConfig.java +++ /dev/null @@ -1,94 +0,0 @@ -package benchmark.config; - -import benchmark.PgClients; -import io.reactiverse.pgclient.PgClient; -import io.reactiverse.pgclient.PgPool; -import io.reactiverse.pgclient.PgPoolOptions; -import io.vertx.core.Vertx; -import org.springframework.boot.context.properties.ConfigurationProperties; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.Profile; - -import java.util.ArrayList; -import java.util.List; - -@Configuration -@Profile("pgclient") -@ConfigurationProperties(prefix = "database") -public class PgClientConfig { - private String name; - private String host; - private int port; - private String username; - private String password; - - @Bean - Vertx vertx() { - return Vertx.vertx(); - } - - @Bean - PgClients pgClients(Vertx vertx) { - List clients = new ArrayList<>(); - - for (int i = 0; i < Runtime.getRuntime().availableProcessors(); i++) { - clients.add(pgClient(vertx)); - } - - return new PgClients(clients); - } - - - public PgPool pgClient(Vertx vertx) { - PgPoolOptions options = new PgPoolOptions(); - options.setDatabase(name); - options.setHost(host); - options.setPort(port); - options.setUser(username); - options.setPassword(password); - options.setCachePreparedStatements(true); - options.setMaxSize(1); - return PgClient.pool(vertx, options); - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public String getHost() { - return host; - } - - public void setHost(String host) { - this.host = host; - } - - public int getPort() { - return port; - } - - public void setPort(int port) { - this.port = port; - } - - public String getUsername() { - return username; - } - - public void setUsername(String username) { - this.username = username; - } - - public String getPassword() { - return password; - } - - public void setPassword(String password) { - this.password = password; - } -} diff --git a/frameworks/Java/spring-webflux/src/main/java/benchmark/config/R2dbcConfig.java b/frameworks/Java/spring-webflux/src/main/java/benchmark/config/R2dbcConfig.java deleted file mode 100644 index 5a0de452252..00000000000 --- a/frameworks/Java/spring-webflux/src/main/java/benchmark/config/R2dbcConfig.java +++ /dev/null @@ -1,63 +0,0 @@ -package benchmark.config; - - -import io.r2dbc.spi.ConnectionFactories; -import io.r2dbc.spi.ConnectionFactory; - -import io.r2dbc.spi.ConnectionFactoryOptions; -import org.springframework.boot.context.properties.ConfigurationProperties; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.Profile; -import org.springframework.r2dbc.core.DatabaseClient; - -import static io.r2dbc.spi.ConnectionFactoryOptions.*; - -@Configuration -@Profile("r2dbc") -@ConfigurationProperties(prefix = "database") -public class R2dbcConfig { - private String name; - private String host; - private int port; - private String username; - private String password; - - public void setName(String name) { - this.name = name; - } - - public void setHost(String host) { - this.host = host; - } - - public void setPort(int port) { - this.port = port; - } - - public void setUsername(String username) { - this.username = username; - } - - public void setPassword(String password) { - this.password = password; - } - - @Bean - ConnectionFactory connectionFactory() { - return ConnectionFactories.get(ConnectionFactoryOptions.builder() - .option(DRIVER,"pool") - .option(PROTOCOL,"postgresql") - .option(HOST, host) - .option(PORT, port) - .option(USER, username) - .option(PASSWORD, password) - .option(DATABASE, name) - .build()); - } - - @Bean - DatabaseClient databaseClient(ConnectionFactory connectionFactory) { - return DatabaseClient.create(connectionFactory); - } -} \ No newline at end of file diff --git a/frameworks/Java/spring-webflux/src/main/java/benchmark/config/ReactiveMongoConfig.java b/frameworks/Java/spring-webflux/src/main/java/benchmark/config/ReactiveMongoConfig.java deleted file mode 100644 index e12178be400..00000000000 --- a/frameworks/Java/spring-webflux/src/main/java/benchmark/config/ReactiveMongoConfig.java +++ /dev/null @@ -1,54 +0,0 @@ -package benchmark.config; - -import com.mongodb.reactivestreams.client.MongoClient; -import com.mongodb.reactivestreams.client.MongoClients; -import org.slf4j.LoggerFactory; -import org.springframework.boot.context.properties.ConfigurationProperties; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.Profile; -import org.springframework.data.mongodb.config.AbstractReactiveMongoConfiguration; -import org.springframework.data.mongodb.core.ReactiveMongoTemplate; -import org.springframework.data.mongodb.repository.config.EnableReactiveMongoRepositories; - -@Configuration -@EnableReactiveMongoRepositories -@Profile("mongo") -@ConfigurationProperties(prefix = "database") -public class ReactiveMongoConfig extends AbstractReactiveMongoConfiguration { - private String url; - private String name; - - @Override - @Bean - public MongoClient reactiveMongoClient() { - LoggerFactory.getLogger(getClass()).info("Connecting to mongo url: {}/{}", url, name); - return MongoClients.create(url); - } - - @Override - protected String getDatabaseName() { - return name; - } - - @Bean - ReactiveMongoTemplate reactiveMongoTemplate() { - return new ReactiveMongoTemplate(reactiveMongoClient(), getDatabaseName()); - } - - public String getUrl() { - return url; - } - - public void setUrl(String url) { - this.url = url; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } -} diff --git a/frameworks/Java/spring-webflux/src/main/java/benchmark/config/RxJdbcConfig.java b/frameworks/Java/spring-webflux/src/main/java/benchmark/config/RxJdbcConfig.java deleted file mode 100644 index f4f5916252d..00000000000 --- a/frameworks/Java/spring-webflux/src/main/java/benchmark/config/RxJdbcConfig.java +++ /dev/null @@ -1,25 +0,0 @@ -package benchmark.config; - -import org.davidmoten.rx.jdbc.ConnectionProvider; -import org.davidmoten.rx.jdbc.Database; -import org.davidmoten.rx.jdbc.pool.NonBlockingConnectionPool; -import org.davidmoten.rx.jdbc.pool.Pools; -import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.Profile; - -@Configuration -@Profile("rxjdbc") -public class RxJdbcConfig { - @Bean - Database database(DataSourceProperties dsProps) { - NonBlockingConnectionPool pool = - Pools.nonBlocking() - .maxPoolSize(Runtime.getRuntime().availableProcessors() * 2) - .connectionProvider(ConnectionProvider.from(dsProps.getUrl(), dsProps.getUsername(), dsProps.getPassword())) - .build(); - - return Database.from(pool); - } -} \ No newline at end of file diff --git a/frameworks/Java/spring-webflux/src/main/java/benchmark/model/Message.java b/frameworks/Java/spring-webflux/src/main/java/benchmark/model/Message.java new file mode 100644 index 00000000000..8a94c8d3ed1 --- /dev/null +++ b/frameworks/Java/spring-webflux/src/main/java/benchmark/model/Message.java @@ -0,0 +1,15 @@ +package benchmark.model; + +public class Message { + + private final String message; + + public Message(String message) { + this.message = message; + } + + public String getMessage() { + return message; + } + +} \ No newline at end of file diff --git a/frameworks/Java/spring-webflux/src/main/java/benchmark/repository/MongoDbRepository.java b/frameworks/Java/spring-webflux/src/main/java/benchmark/repository/MongoDbRepository.java index 7e6b51ff39a..df777dd2d8e 100644 --- a/frameworks/Java/spring-webflux/src/main/java/benchmark/repository/MongoDbRepository.java +++ b/frameworks/Java/spring-webflux/src/main/java/benchmark/repository/MongoDbRepository.java @@ -5,7 +5,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.context.annotation.Profile; -import org.springframework.data.mongodb.core.ReactiveMongoTemplate; +import org.springframework.data.mongodb.core.ReactiveMongoOperations; import org.springframework.stereotype.Component; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; @@ -18,22 +18,21 @@ @Component @Profile("mongo") public class MongoDbRepository implements DbRepository { - private final Logger log = LoggerFactory.getLogger(getClass()); - private final ReactiveMongoTemplate mongoTemplate; - public MongoDbRepository(ReactiveMongoTemplate mongoTemplate) { - this.mongoTemplate = mongoTemplate; + private final ReactiveMongoOperations operations; + + public MongoDbRepository(ReactiveMongoOperations operations) { + this.operations = operations; } @Override public Mono getWorld(int id) { - log.debug("getWorld({})", id); - return mongoTemplate.findById(id, World.class); + return operations.findById(id, World.class); } @Override public Mono findAndUpdateWorld(int id, int randomNumber) { - return mongoTemplate.findAndModify( + return operations.findAndModify( query(where("id").is(id)), update("randomNumber", randomNumber), options().returnNew(true), @@ -42,6 +41,6 @@ public Mono findAndUpdateWorld(int id, int randomNumber) { @Override public Flux fortunes() { - return mongoTemplate.findAll(Fortune.class); + return operations.findAll(Fortune.class); } } \ No newline at end of file diff --git a/frameworks/Java/spring-webflux/src/main/java/benchmark/repository/PgClientDbRepository.java b/frameworks/Java/spring-webflux/src/main/java/benchmark/repository/PgClientDbRepository.java deleted file mode 100644 index 50dc6286ea1..00000000000 --- a/frameworks/Java/spring-webflux/src/main/java/benchmark/repository/PgClientDbRepository.java +++ /dev/null @@ -1,79 +0,0 @@ -package benchmark.repository; - -import benchmark.PgClients; -import benchmark.model.Fortune; -import benchmark.model.World; -import io.reactiverse.pgclient.PgIterator; -import io.reactiverse.pgclient.Row; -import io.reactiverse.pgclient.Tuple; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.context.annotation.Profile; -import org.springframework.stereotype.Component; -import reactor.core.publisher.Flux; -import reactor.core.publisher.Mono; - -@Component -@Profile("pgclient") -public class PgClientDbRepository implements DbRepository { - private final Logger log = LoggerFactory.getLogger(getClass()); - private final PgClients pgClients; - - public PgClientDbRepository(PgClients pgClients) { - this.pgClients = pgClients; - } - - @Override - public Mono getWorld(int id) { - return Mono.create(sink -> - pgClients.getOne().preparedQuery("SELECT * FROM world WHERE id = $1", Tuple.of(id), ar -> { - if (ar.failed()) { - sink.error(ar.cause()); - } else { - - final Row row = ar.result().iterator().next(); - - World world = new World(row.getInteger(0), row.getInteger(1)); - sink.success(world); - } - })); - } - - private Mono updateWorld(World world) { - return Mono.create(sink -> { - pgClients.getOne().preparedQuery("UPDATE world SET randomnumber = $1 WHERE id = $2", Tuple.of(world.randomnumber, world.id), ar -> { - if (ar.failed()) { - sink.error(ar.cause()); - } else { - sink.success(world); - } - }); - }); - } - - @Override - public Mono findAndUpdateWorld(int id, int randomNumber) { - return getWorld(id).flatMap(world -> { - world.randomnumber = randomNumber; - return updateWorld(world); - }); - } - - @Override - public Flux fortunes() { - return Flux.create(sink -> - pgClients.getOne().preparedQuery("SELECT * FROM fortune", ar -> { - if (ar.failed()) { - sink.error(ar.cause()); - return; - } - - PgIterator resultSet = ar.result().iterator(); - while (resultSet.hasNext()) { - Tuple row = resultSet.next(); - sink.next(new Fortune(row.getInteger(0), row.getString(1))); - } - sink.complete(); - })); - } -} \ No newline at end of file diff --git a/frameworks/Java/spring-webflux/src/main/java/benchmark/repository/R2dbcDbRepository.java b/frameworks/Java/spring-webflux/src/main/java/benchmark/repository/R2dbcDbRepository.java index e5915fc05d7..c7cfb89dea4 100644 --- a/frameworks/Java/spring-webflux/src/main/java/benchmark/repository/R2dbcDbRepository.java +++ b/frameworks/Java/spring-webflux/src/main/java/benchmark/repository/R2dbcDbRepository.java @@ -22,7 +22,7 @@ public Mono getWorld(int id) { return databaseClient .sql("SELECT id, randomnumber FROM world WHERE id = $1") .bind("$1", id) - .map((row, rowMetaData) -> new World(row.get("id", Integer.class), row.get("randomnumber", Integer.class))) + .mapProperties(World.class) .first(); } @@ -48,7 +48,7 @@ public Mono findAndUpdateWorld(int id, int randomNumber) { public Flux fortunes() { return databaseClient .sql("SELECT id, message FROM fortune") - .map((row, rowMetaData) -> new Fortune(row.get("id", Integer.class), row.get("message", String.class))) + .mapProperties(Fortune.class) .all(); } } \ No newline at end of file diff --git a/frameworks/Java/spring-webflux/src/main/java/benchmark/repository/RxJdbcDbRepository.java b/frameworks/Java/spring-webflux/src/main/java/benchmark/repository/RxJdbcDbRepository.java deleted file mode 100644 index 1d07720f391..00000000000 --- a/frameworks/Java/spring-webflux/src/main/java/benchmark/repository/RxJdbcDbRepository.java +++ /dev/null @@ -1,60 +0,0 @@ -package benchmark.repository; - -import benchmark.model.Fortune; -import benchmark.model.World; -import io.reactivex.Flowable; -import org.davidmoten.rx.jdbc.Database; -import org.springframework.context.annotation.Profile; -import org.springframework.stereotype.Component; -import reactor.core.publisher.Flux; -import reactor.core.publisher.Mono; - -@Component -@Profile("rxjdbc") -public class RxJdbcDbRepository implements DbRepository { - private final Database db; - - public RxJdbcDbRepository(Database db) { - this.db = db; - } - - @Override - public Mono getWorld(int id) { - String sql = "SELECT * FROM world WHERE id = ?"; - - Flowable worldFlowable = db.select(sql) - .parameters(id) - .get(rs -> { - World world = new World(rs.getInt("id"), rs.getInt("randomnumber")); - return world; - }); - - return Mono.from(worldFlowable); - } - - public Mono updateWorld(World world) { - String sql = "UPDATE world SET randomnumber = ? WHERE id = ?"; - - Flowable worldFlowable = db.update(sql) - .parameters(world.randomnumber, world.id) - .counts().map(cnt -> world); - return Mono.from(worldFlowable); - } - - public Mono findAndUpdateWorld(int id, int randomNumber) { - return getWorld(id).flatMap(world -> { - world.randomnumber = randomNumber; - return updateWorld(world); - }); - } - - @Override - public Flux fortunes() { - String sql = "SELECT * FROM fortune"; - - Flowable fortuneFlowable = db.select(sql) - .get(rs -> new Fortune(rs.getInt("id"), rs.getString("message"))); - - return Flux.from(fortuneFlowable); - } -} \ No newline at end of file diff --git a/frameworks/Java/spring-webflux/src/main/java/benchmark/web/WebfluxHandler.java b/frameworks/Java/spring-webflux/src/main/java/benchmark/web/WebfluxHandler.java index e7fdeafa404..a7516af6636 100644 --- a/frameworks/Java/spring-webflux/src/main/java/benchmark/web/WebfluxHandler.java +++ b/frameworks/Java/spring-webflux/src/main/java/benchmark/web/WebfluxHandler.java @@ -1,8 +1,16 @@ package benchmark.web; +import java.util.Collections; +import java.util.List; +import java.util.Optional; +import java.util.concurrent.ThreadLocalRandom; + import benchmark.model.Fortune; +import benchmark.model.Message; import benchmark.model.World; import benchmark.repository.DbRepository; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; import org.springframework.core.ParameterizedTypeReference; import org.springframework.http.MediaType; @@ -10,16 +18,11 @@ import org.springframework.web.reactive.function.server.ServerRequest; import org.springframework.web.reactive.function.server.ServerResponse; -import reactor.core.publisher.Flux; -import reactor.core.publisher.Mono; - -import java.util.*; -import java.util.concurrent.ThreadLocalRandom; - import static java.util.Comparator.comparing; @Component public class WebfluxHandler { + private final DbRepository dbRepository; public WebfluxHandler(DbRepository dbRepository) { @@ -29,13 +32,13 @@ public WebfluxHandler(DbRepository dbRepository) { public Mono plaintext(ServerRequest request) { return ServerResponse.ok() .contentType(MediaType.TEXT_PLAIN) - .body(Mono.just("Hello, World!"), String.class); + .bodyValue("Hello, World!"); } public Mono json(ServerRequest request) { return ServerResponse.ok() .contentType(MediaType.APPLICATION_JSON) - .body(Mono.just(Map.of("message", "Hello, World!")), Map.class); + .bodyValue(new Message("Hello, World!")); } public Mono db(ServerRequest request) { @@ -76,7 +79,7 @@ private static int parseQueryCount(Optional maybeTextValue) { public Mono updates(ServerRequest request) { int queries = getQueries(request); - + Mono> worlds = Flux.range(0, queries) .flatMap(i -> dbRepository.findAndUpdateWorld(randomWorldNumber(), randomWorldNumber())) .collectList(); @@ -105,4 +108,4 @@ private static int getQueries(ServerRequest request) { private static int randomWorldNumber() { return 1 + ThreadLocalRandom.current().nextInt(10000); } -} +} \ No newline at end of file diff --git a/frameworks/Java/spring-webflux/src/main/java/benchmark/web/WebfluxRouter.java b/frameworks/Java/spring-webflux/src/main/java/benchmark/web/WebfluxRouter.java index 7d1ad9c881a..061797738c2 100644 --- a/frameworks/Java/spring-webflux/src/main/java/benchmark/web/WebfluxRouter.java +++ b/frameworks/Java/spring-webflux/src/main/java/benchmark/web/WebfluxRouter.java @@ -6,32 +6,18 @@ import org.springframework.web.reactive.function.server.RouterFunctions; import org.springframework.web.reactive.function.server.ServerResponse; -import static org.springframework.web.reactive.function.server.RequestPredicates.GET; - @Configuration public class WebfluxRouter { @Bean - RouterFunction route(WebfluxHandler handler) { - return RouterFunctions - .route( - GET("/plaintext"), - handler::plaintext) - .andRoute( - GET("/json"), - handler::json) - .andRoute( - GET("/db"), - handler::db) - .andRoute( - GET("/queries"), - handler::queries) - .andRoute( - GET("/updates"), - handler::updates) - .andRoute( - GET("/fortunes"), - handler::fortunes) - ; + public RouterFunction route(WebfluxHandler handler) { + return RouterFunctions.route() + .GET("/plaintext", handler::plaintext) + .GET("/json", handler::json) + .GET("/db", handler::db) + .GET("/queries", handler::queries) + .GET("/updates", handler::updates) + .GET("/fortunes", handler::fortunes) + .build(); } } \ No newline at end of file diff --git a/frameworks/Java/spring-webflux/src/main/resources/application.yml b/frameworks/Java/spring-webflux/src/main/resources/application.yml index d315f4353ee..af7743831e3 100755 --- a/frameworks/Java/spring-webflux/src/main/resources/application.yml +++ b/frameworks/Java/spring-webflux/src/main/resources/application.yml @@ -1,17 +1,3 @@ -spring: - jpa: - open-in-view: false - ---- -spring: - config: - activate: - on-profile: postgres - datasource: - url: jdbc:postgresql://${database.host}:${database.port}/${database.name} - username: ${database.username} - password: ${database.password} - database: name: hello_world host: tfb-database @@ -19,45 +5,17 @@ database: username: benchmarkdbuser password: benchmarkdbpass ---- -spring: - config: - activate: - on-profile: jdbc - autoconfigure: - exclude: - - org.springframework.boot.autoconfigure.data.mongo.MongoReactiveDataAutoConfiguration - - org.springframework.boot.autoconfigure.r2dbc.R2dbcAutoConfiguration - ---- -spring: - config: - activate: - on-profile: pgclient - autoconfigure: - exclude: - - org.springframework.boot.autoconfigure.data.mongo.MongoReactiveDataAutoConfiguration - - org.springframework.boot.autoconfigure.r2dbc.R2dbcAutoConfiguration - ---- -spring: - config: - activate: - on-profile: rxjdbc - autoconfigure: - exclude: - - org.springframework.boot.autoconfigure.data.mongo.MongoReactiveDataAutoConfiguration - - org.springframework.boot.autoconfigure.r2dbc.R2dbcAutoConfiguration - --- spring: config: activate: on-profile: r2dbc autoconfigure: - exclude: - - org.springframework.boot.autoconfigure.data.mongo.MongoReactiveDataAutoConfiguration - - org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration + exclude: org.springframework.boot.autoconfigure.mongo.MongoReactiveAutoConfiguration,org.springframework.boot.autoconfigure.data.mongo.MongoReactiveDataAutoConfiguration + r2dbc: + username: ${database.username} + password: ${database.password} + url: r2dbc:postgresql://${database.host}:${database.port}/${database.name} --- spring: @@ -65,10 +23,9 @@ spring: activate: on-profile: mongo autoconfigure: - exclude: - - org.springframework.boot.autoconfigure.r2dbc.R2dbcAutoConfiguration - - org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration + exclude: org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration,org.springframework.boot.autoconfigure.r2dbc.R2dbcAutoConfiguration -database: - url: mongodb://tfb-database:27017/?waitQueueMultiple=200 - name: hello_world \ No newline at end of file + data: + mongodb: + uri: mongodb://tfb-database:27017/?waitQueueMultiple=200 + database: hello_world diff --git a/frameworks/Java/spring/pom.xml b/frameworks/Java/spring/pom.xml index 4e390ebc4f6..9f131b9a23f 100644 --- a/frameworks/Java/spring/pom.xml +++ b/frameworks/Java/spring/pom.xml @@ -11,11 +11,11 @@ org.springframework.boot spring-boot-starter-parent - 3.3.0 + 3.3.1 - 17 + 21 @@ -61,9 +61,6 @@ org.apache.maven.plugins maven-compiler-plugin - - false - diff --git a/frameworks/Java/spring/spring-jpa.dockerfile b/frameworks/Java/spring/spring-jpa.dockerfile index 4af1b98a73f..0598e9c1f28 100644 --- a/frameworks/Java/spring/spring-jpa.dockerfile +++ b/frameworks/Java/spring/spring-jpa.dockerfile @@ -1,15 +1,15 @@ -FROM maven:3.9.6-eclipse-temurin-21 as maven -RUN mvn -version +FROM maven:3.9.5-eclipse-temurin-21 as maven WORKDIR /spring COPY src src COPY pom.xml pom.xml RUN mvn package -q -FROM eclipse-temurin:21.0.3_9-jre-jammy -RUN java -version +FROM bellsoft/liberica-openjre-debian:21 WORKDIR /spring COPY --from=maven /spring/target/hello-spring-1.0-SNAPSHOT.jar app.jar +# See https://docs.spring.io/spring-boot/reference/packaging/efficient.html +RUN java -Djarmode=tools -jar app.jar extract EXPOSE 8080 -CMD ["java", "-server", "-XX:+UseNUMA", "-XX:+UseG1GC", "-XX:+DisableExplicitGC", "-XX:+UseStringDeduplication", "-Dlogging.level.root=OFF", "-jar", "app.jar", "--spring.profiles.active=jpa"] +CMD ["java", "-XX:+DisableExplicitGC", "-XX:+UseStringDeduplication", "-Dlogging.level.root=OFF", "-jar", "app/app.jar", "--spring.profiles.active=jpa"] \ No newline at end of file diff --git a/frameworks/Java/spring/spring-mongo.dockerfile b/frameworks/Java/spring/spring-mongo.dockerfile index 4fa82a28d5d..e700a21cabd 100644 --- a/frameworks/Java/spring/spring-mongo.dockerfile +++ b/frameworks/Java/spring/spring-mongo.dockerfile @@ -1,15 +1,15 @@ -FROM maven:3.9.6-eclipse-temurin-21 as maven -RUN mvn -version +FROM maven:3.9.5-eclipse-temurin-21 as maven WORKDIR /spring COPY src src COPY pom.xml pom.xml RUN mvn package -q -FROM eclipse-temurin:21.0.3_9-jre-jammy -RUN java -version +FROM bellsoft/liberica-openjre-debian:21 WORKDIR /spring COPY --from=maven /spring/target/hello-spring-1.0-SNAPSHOT.jar app.jar +# See https://docs.spring.io/spring-boot/reference/packaging/efficient.html +RUN java -Djarmode=tools -jar app.jar extract EXPOSE 8080 -CMD ["java", "-server", "-XX:+UseNUMA", "-XX:+UseG1GC", "-XX:+DisableExplicitGC", "-XX:+UseStringDeduplication", "-Dlogging.level.root=OFF", "-jar", "app.jar", "--spring.profiles.active=mongo"] +CMD ["java", "-XX:+DisableExplicitGC", "-XX:+UseStringDeduplication", "-Dlogging.level.root=OFF", "-jar", "app/app.jar", "--spring.profiles.active=mongo"] \ No newline at end of file diff --git a/frameworks/Java/spring/spring.dockerfile b/frameworks/Java/spring/spring.dockerfile index f6f5145477f..0598e9c1f28 100644 --- a/frameworks/Java/spring/spring.dockerfile +++ b/frameworks/Java/spring/spring.dockerfile @@ -1,15 +1,15 @@ -FROM maven:3.9.6-eclipse-temurin-21 as maven -RUN mvn -version +FROM maven:3.9.5-eclipse-temurin-21 as maven WORKDIR /spring COPY src src COPY pom.xml pom.xml RUN mvn package -q -FROM eclipse-temurin:21.0.3_9-jre-jammy -RUN java -version +FROM bellsoft/liberica-openjre-debian:21 WORKDIR /spring COPY --from=maven /spring/target/hello-spring-1.0-SNAPSHOT.jar app.jar +# See https://docs.spring.io/spring-boot/reference/packaging/efficient.html +RUN java -Djarmode=tools -jar app.jar extract EXPOSE 8080 -CMD ["java", "-server", "-XX:+UseNUMA", "-XX:+DisableExplicitGC", "-XX:+UseStringDeduplication", "-Dlogging.level.root=OFF", "-jar", "app.jar", "--spring.profiles.active=jdbc"] +CMD ["java", "-XX:+DisableExplicitGC", "-XX:+UseStringDeduplication", "-Dlogging.level.root=OFF", "-jar", "app/app.jar", "--spring.profiles.active=jpa"] \ No newline at end of file diff --git a/frameworks/Java/spring/src/main/java/hello/App.java b/frameworks/Java/spring/src/main/java/hello/App.java index 0ab1327f8c4..d0c13e06844 100644 --- a/frameworks/Java/spring/src/main/java/hello/App.java +++ b/frameworks/Java/spring/src/main/java/hello/App.java @@ -14,7 +14,7 @@ import com.zaxxer.hikari.HikariDataSource; -@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class, MongoRepositoriesAutoConfiguration.class}) +@SpringBootApplication public class App { public static void main(String[] args) { diff --git a/frameworks/Java/spring/src/main/java/hello/controller/HelloController.java b/frameworks/Java/spring/src/main/java/hello/controller/HelloController.java index 3c891567942..5c11b82ac66 100644 --- a/frameworks/Java/spring/src/main/java/hello/controller/HelloController.java +++ b/frameworks/Java/spring/src/main/java/hello/controller/HelloController.java @@ -6,6 +6,7 @@ import java.util.concurrent.ThreadLocalRandom; import java.util.stream.IntStream; +import hello.model.Message; import jakarta.servlet.http.HttpServletResponse; import org.springframework.http.MediaType; import org.springframework.web.bind.annotation.GetMapping; @@ -31,7 +32,7 @@ public HelloController( this.updateWorldService = updateWorldService; } - @GetMapping(value = "/plaintext") + @GetMapping("/plaintext") String plaintext(HttpServletResponse response) { response.setContentType(MediaType.TEXT_PLAIN_VALUE); return "Hello, World!"; @@ -102,16 +103,4 @@ private static int parseQueryCount(String textValue) { } return Math.min(500, Math.max(1, parsedValue)); } - - static class Message { - private final String message; - - public Message(String message) { - this.message = message; - } - - public String getMessage() { - return message; - } - } } diff --git a/frameworks/Java/spring/src/main/java/hello/model/Message.java b/frameworks/Java/spring/src/main/java/hello/model/Message.java new file mode 100644 index 00000000000..4c675c8a162 --- /dev/null +++ b/frameworks/Java/spring/src/main/java/hello/model/Message.java @@ -0,0 +1,15 @@ +package hello.model; + +public class Message { + + private final String message; + + public Message(String message) { + this.message = message; + } + + public String getMessage() { + return message; + } + +} \ No newline at end of file diff --git a/frameworks/Java/spring/src/main/resources/application.yml b/frameworks/Java/spring/src/main/resources/application.yml index 42c14602858..4796669a8e5 100644 --- a/frameworks/Java/spring/src/main/resources/application.yml +++ b/frameworks/Java/spring/src/main/resources/application.yml @@ -1,10 +1,15 @@ --- spring: - threads: - virtual: - enabled: true jpa: open-in-view: false + config: + activate: + on-profile: jdbc + autoconfigure: + exclude: org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration,org.springframework.boot.autoconfigure.data.jpa.JpaRepositoriesAutoConfiguration,org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration,org.springframework.boot.autoconfigure.data.mongo.MongoRepositoriesAutoConfiguration + +--- +spring: config: activate: on-profile: jdbc,jpa @@ -25,6 +30,8 @@ spring: config: activate: on-profile: jpa + autoconfigure: + exclude: org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration,org.springframework.boot.autoconfigure.data.mongo.MongoRepositoriesAutoConfiguration jpa: database-platform: org.hibernate.dialect.PostgreSQLDialect @@ -33,6 +40,8 @@ spring: config: activate: on-profile: mongo + autoconfigure: + exclude: org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration,org.springframework.boot.autoconfigure.data.jpa.JpaRepositoriesAutoConfiguration,org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration spring.data.mongodb: host: tfb-database @@ -45,4 +54,4 @@ spring: active: jdbc server.server-header: Spring -server.servlet.encoding.force: true \ No newline at end of file +server.servlet.encoding.force: true From 848d6840769d21e4a39eebc7b902e2d05ea04166 Mon Sep 17 00:00:00 2001 From: Andrew McCloskey Date: Fri, 2 Aug 2024 11:59:56 -0400 Subject: [PATCH 055/204] initial commit of vertx-web-kotlin-dsljson benchmark (#9172) * initial commit of vertx-web-kotlin-dsljson benchmark * removed dagger. improved query performance. --- .../vertx-web-kotlin-dsljson/.gitattributes | 9 + .../Kotlin/vertx-web-kotlin-dsljson/README.md | 36 ++ .../benchmark_config.json | 47 +++ .../vertx-web-kotlin-dsljson/build.gradle.kts | 86 +++++ .../configuration/scripts/server.sh | 47 +++ .../gradle.properties | 1 + .../gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 43504 bytes .../gradle/wrapper/gradle-wrapper.properties | 7 + .../Kotlin/vertx-web-kotlin-dsljson/gradlew | 252 ++++++++++++ .../vertx-web-kotlin-dsljson/gradlew.bat | 94 +++++ .../settings.gradle.kts | 1 + .../main/kotlin/com/example/starter/App.kt | 50 +++ .../com/example/starter/BasicVerticle.kt | 56 +++ .../com/example/starter/PostgresVerticle.kt | 88 +++++ .../example/starter/db/AbstractRepository.kt | 7 + .../example/starter/db/FortuneRepository.kt | 23 ++ .../com/example/starter/db/WorldRepository.kt | 84 ++++ .../starter/handlers/AbstractHandler.kt | 57 +++ .../starter/handlers/DefaultHandler.kt | 15 + .../starter/handlers/FortuneHandler.kt | 57 +++ .../starter/handlers/MessageHandler.kt | 15 + .../example/starter/handlers/WorldHandler.kt | 56 +++ .../example/starter/io/BufferOutputStream.kt | 362 ++++++++++++++++++ .../com/example/starter/io/JsonResource.kt | 15 + .../com/example/starter/models/Fortune.kt | 14 + .../com/example/starter/models/Message.kt | 7 + .../com/example/starter/models/World.kt | 14 + .../example/starter/utils/FutureExtensions.kt | 14 + .../example/starter/utils/JsonExtensions.kt | 19 + .../starter/utils/PeriodicDateResolver.kt | 16 + .../example/starter/utils/RowSetExtensions.kt | 14 + .../starter/utils/ThrowableExtensions.kt | 12 + .../main/resources/http-server-options.json | 6 + .../src/main/resources/log4j2.xml | 13 + .../main/resources/pg-connect-options.json | 15 + ...x-web-kotlin-dsljson-postgresql.dockerfile | 37 ++ .../vertx-web-kotlin-dsljson.dockerfile | 37 ++ 37 files changed, 1683 insertions(+) create mode 100644 frameworks/Kotlin/vertx-web-kotlin-dsljson/.gitattributes create mode 100644 frameworks/Kotlin/vertx-web-kotlin-dsljson/README.md create mode 100644 frameworks/Kotlin/vertx-web-kotlin-dsljson/benchmark_config.json create mode 100644 frameworks/Kotlin/vertx-web-kotlin-dsljson/build.gradle.kts create mode 100644 frameworks/Kotlin/vertx-web-kotlin-dsljson/configuration/scripts/server.sh create mode 100644 frameworks/Kotlin/vertx-web-kotlin-dsljson/gradle.properties create mode 100644 frameworks/Kotlin/vertx-web-kotlin-dsljson/gradle/wrapper/gradle-wrapper.jar create mode 100644 frameworks/Kotlin/vertx-web-kotlin-dsljson/gradle/wrapper/gradle-wrapper.properties create mode 100644 frameworks/Kotlin/vertx-web-kotlin-dsljson/gradlew create mode 100644 frameworks/Kotlin/vertx-web-kotlin-dsljson/gradlew.bat create mode 100644 frameworks/Kotlin/vertx-web-kotlin-dsljson/settings.gradle.kts create mode 100644 frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/App.kt create mode 100644 frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/BasicVerticle.kt create mode 100644 frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/PostgresVerticle.kt create mode 100644 frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/db/AbstractRepository.kt create mode 100644 frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/db/FortuneRepository.kt create mode 100644 frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/db/WorldRepository.kt create mode 100644 frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/handlers/AbstractHandler.kt create mode 100644 frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/handlers/DefaultHandler.kt create mode 100644 frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/handlers/FortuneHandler.kt create mode 100644 frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/handlers/MessageHandler.kt create mode 100644 frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/handlers/WorldHandler.kt create mode 100644 frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/io/BufferOutputStream.kt create mode 100644 frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/io/JsonResource.kt create mode 100644 frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/models/Fortune.kt create mode 100644 frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/models/Message.kt create mode 100644 frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/models/World.kt create mode 100644 frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/utils/FutureExtensions.kt create mode 100644 frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/utils/JsonExtensions.kt create mode 100644 frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/utils/PeriodicDateResolver.kt create mode 100644 frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/utils/RowSetExtensions.kt create mode 100644 frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/utils/ThrowableExtensions.kt create mode 100644 frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/resources/http-server-options.json create mode 100644 frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/resources/log4j2.xml create mode 100644 frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/resources/pg-connect-options.json create mode 100644 frameworks/Kotlin/vertx-web-kotlin-dsljson/vertx-web-kotlin-dsljson-postgresql.dockerfile create mode 100644 frameworks/Kotlin/vertx-web-kotlin-dsljson/vertx-web-kotlin-dsljson.dockerfile diff --git a/frameworks/Kotlin/vertx-web-kotlin-dsljson/.gitattributes b/frameworks/Kotlin/vertx-web-kotlin-dsljson/.gitattributes new file mode 100644 index 00000000000..097f9f98d9e --- /dev/null +++ b/frameworks/Kotlin/vertx-web-kotlin-dsljson/.gitattributes @@ -0,0 +1,9 @@ +# +# https://help.github.com/articles/dealing-with-line-endings/ +# +# Linux start script should use lf +/gradlew text eol=lf + +# These are Windows script files and should use crlf +*.bat text eol=crlf + diff --git a/frameworks/Kotlin/vertx-web-kotlin-dsljson/README.md b/frameworks/Kotlin/vertx-web-kotlin-dsljson/README.md new file mode 100644 index 00000000000..b8ae3f33b30 --- /dev/null +++ b/frameworks/Kotlin/vertx-web-kotlin-dsljson/README.md @@ -0,0 +1,36 @@ +# Vert.x-Web Kotlin Dsljson Benchmarking Test + +Vert.x-Web in Kotlin with Dsljson serialization + +The code is written as a realistic server implementation: +- Code is organized logically into packages +- Repositories are created for each database entity to handler all operations pertaining to a specific table +- Handlers map to the logical entities which they serve +- JSON serialization is provided via Dsljson + - Doing this effectively required a custom Vert.x Buffer implementation that also extended OutputStream in order to rely on the efficient Vert.x heap memory pool instead of building a novel implementation. + +## Test URLs + +### JSON + +http://localhost:8080/json + +### PLAINTEXT + +http://localhost:8080/plaintext + +### DB + +http://localhost:8080/db + +### QUERY + +http://localhost:8080/query?queries= + +### UPDATE + +http://localhost:8080/update?queries= + +### FORTUNES + +http://localhost:8080/fortunes diff --git a/frameworks/Kotlin/vertx-web-kotlin-dsljson/benchmark_config.json b/frameworks/Kotlin/vertx-web-kotlin-dsljson/benchmark_config.json new file mode 100644 index 00000000000..445d7e5f319 --- /dev/null +++ b/frameworks/Kotlin/vertx-web-kotlin-dsljson/benchmark_config.json @@ -0,0 +1,47 @@ +{ + "framework": "vertx-web-kotlin-dsljson", + "tests": [ + { + "default": { + "json_url": "/json", + "plaintext_url": "/plaintext", + "port": 8080, + "approach": "Realistic", + "classification": "Micro", + "database": "None", + "framework": "vertx-web", + "language": "Kotlin", + "flavor": "None", + "orm": "Raw", + "platform": "Vert.x", + "webserver": "None", + "os": "Linux", + "database_os": "Linux", + "display_name": "vertx-web-kotlin-dsljson", + "notes": "", + "versus": "vertx-web" + }, + "postgresql": { + "db_url": "/db", + "query_url": "/queries?queries=", + "fortune_url": "/fortunes", + "update_url": "/updates?queries=", + "port": 8080, + "approach": "Realistic", + "classification": "Micro", + "database": "postgres", + "framework": "vertx-web", + "language": "Kotlin", + "flavor": "None", + "orm": "Raw", + "platform": "Vert.x", + "webserver": "None", + "os": "Linux", + "database_os": "Linux", + "display_name": "vertx-web-kotlin-dsljson-postgresql", + "notes": "", + "versus": "vertx-web-postgres" + } + } + ] +} diff --git a/frameworks/Kotlin/vertx-web-kotlin-dsljson/build.gradle.kts b/frameworks/Kotlin/vertx-web-kotlin-dsljson/build.gradle.kts new file mode 100644 index 00000000000..5131d1b9ec7 --- /dev/null +++ b/frameworks/Kotlin/vertx-web-kotlin-dsljson/build.gradle.kts @@ -0,0 +1,86 @@ +import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar +import org.jetbrains.kotlin.gradle.dsl.JvmTarget + +plugins { + kotlin("jvm") version "1.9.22" + kotlin("kapt") version "1.9.22" + application + id("com.github.johnrengelman.shadow") version "7.1.2" +} + +group = "com.example" +version = "1.0.0-SNAPSHOT" + +repositories { + mavenCentral() +} + +java { + toolchain { + languageVersion.set(JavaLanguageVersion.of(21)) + } +} + +kotlin { + compilerOptions { + jvmTarget = JvmTarget.JVM_21 + } + jvmToolchain(21) +} + +val mainClassName = "com.example.starter.App" + +val vertxVersion = "4.5.9" +val nettyVersion = "4.1.112.Final" +val scramVersion = "2.1" +val dslJsonVersion = "2.0.2" +val htmlFlowVersion = "4.6" +val log4jVersion = "2.23.1" + +application { + mainClass = mainClassName +} + +dependencies { + listOfNotNull( + // Kotlin + kotlin("stdlib-jdk8"), + kotlin("reflect"), + + // Vertx + platform("io.vertx:vertx-stack-depchain:$vertxVersion"), + "io.vertx:vertx-core", + "io.vertx:vertx-web", + "io.vertx:vertx-pg-client", + "io.vertx:vertx-lang-kotlin", + "io.vertx:vertx-lang-kotlin-coroutines", + + // Netty + "io.netty:netty-transport-native-epoll:$nettyVersion:linux-x86_64", + + // Postgres + "com.ongres.scram:client:$scramVersion", + + // dsljson + "com.dslplatform:dsl-json:$dslJsonVersion", + + // HtmlFlow + "com.github.xmlet:htmlflow:$htmlFlowVersion", + + // Logging + "org.apache.logging.log4j:log4j-core:$log4jVersion", + "org.apache.logging.log4j:log4j-api:$log4jVersion", + "org.apache.logging.log4j:log4j-api-kotlin:1.4.0", + "com.lmax:disruptor:4.0.0", + ).map { implementation(it) } + + listOf( + "com.dslplatform:dsl-json:$dslJsonVersion", + "org.apache.logging.log4j:log4j-core:$log4jVersion", + ).map { kapt(it) } +} + +tasks.withType { + archiveClassifier = "fat" + mergeServiceFiles() +} diff --git a/frameworks/Kotlin/vertx-web-kotlin-dsljson/configuration/scripts/server.sh b/frameworks/Kotlin/vertx-web-kotlin-dsljson/configuration/scripts/server.sh new file mode 100644 index 00000000000..80e05662a59 --- /dev/null +++ b/frameworks/Kotlin/vertx-web-kotlin-dsljson/configuration/scripts/server.sh @@ -0,0 +1,47 @@ +#!/bin/bash + +NUM_PROCESSORS=$((`grep --count ^processor /proc/cpuinfo`)) + +JVM_OPTS="-server \ + -Xms2G \ + -Xmx2G \ + -XX:+UseParallelGC \ + -XX:InitialCodeCacheSize=512m \ + -XX:ReservedCodeCacheSize=512m \ + -XX:MaxInlineLevel=20 \ + -XX:+AlwaysPreTouch \ + -XX:+UseNUMA \ + -Dvertx.disableMetrics=true \ + -Dvertx.disableH2c=true \ + -Dvertx.disableWebsockets=true \ + -Dvertx.flashPolicyHandler=false \ + -Dvertx.threadChecks=false \ + -Dvertx.disableContextTimings=true \ + -Dvertx.disableTCCL=true \ + -Dvertx.disableHttpHeadersValidation=true \ + -Dlog4j2.contextSelector=org.apache.logging.log4j.core.async.AsyncLoggerContextSelector \ + -Dio.netty.buffer.checkBounds=false \ + -Dio.netty.buffer.checkAccessible=false \ + -Dtfb.hasDB=false" + +JAR_PATH="./build/libs/vertx-web-kotlin-dsljson-benchmark-1.0.0-SNAPSHOT-fat.jar" + +VERTX_ARGS="-instances 1" + +cleanup() { + echo "Caught SIGINT signal. Stopping the Java program..." + if [ ! -z "$JAVA_PID" ]; then + kill -SIGTERM "$JAVA_PID" + wait "$JAVA_PID" + fi + exit 0 +} + +trap cleanup SIGINT + +java $JVM_OPTS -jar $JAR_PATH $VERTX_ARGS & +JAVA_PID=$! + +echo "Server PID: $JAVA_PID" + +wait "$JAVA_PID" diff --git a/frameworks/Kotlin/vertx-web-kotlin-dsljson/gradle.properties b/frameworks/Kotlin/vertx-web-kotlin-dsljson/gradle.properties new file mode 100644 index 00000000000..f97ebb7d334 --- /dev/null +++ b/frameworks/Kotlin/vertx-web-kotlin-dsljson/gradle.properties @@ -0,0 +1 @@ +org.gradle.parallel=true diff --git a/frameworks/Kotlin/vertx-web-kotlin-dsljson/gradle/wrapper/gradle-wrapper.jar b/frameworks/Kotlin/vertx-web-kotlin-dsljson/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..2c3521197d7c4586c843d1d3e9090525f1898cde GIT binary patch literal 43504 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 yu?e%!_ptzGB|8GrCfu%p?(_ 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 TZiJi*F`$tkWLn) literal 0 HcmV?d00001 diff --git a/frameworks/Kotlin/vertx-web-kotlin-dsljson/gradle/wrapper/gradle-wrapper.properties b/frameworks/Kotlin/vertx-web-kotlin-dsljson/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 00000000000..09523c0e549 --- /dev/null +++ b/frameworks/Kotlin/vertx-web-kotlin-dsljson/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,7 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-bin.zip +networkTimeout=10000 +validateDistributionUrl=true +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/frameworks/Kotlin/vertx-web-kotlin-dsljson/gradlew b/frameworks/Kotlin/vertx-web-kotlin-dsljson/gradlew new file mode 100644 index 00000000000..f5feea6d6b1 --- /dev/null +++ b/frameworks/Kotlin/vertx-web-kotlin-dsljson/gradlew @@ -0,0 +1,252 @@ +#!/bin/sh + +# +# Copyright © 2015-2021 the original authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# SPDX-License-Identifier: Apache-2.0 +# + +############################################################################## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# +############################################################################## + +# Attempt to set APP_HOME + +# Resolve links: $0 may be a link +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +# This is normally unused +# shellcheck disable=SC2034 +APP_BASE_NAME=${0##*/} +# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) +APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s +' "$PWD" ) || exit + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + if ! command -v java >/dev/null 2>&1 + then + die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Collect all arguments for the java command: +# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# and any embedded shellness will be escaped. +# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be +# treated as '${Hostname}' itself on the command line. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/frameworks/Kotlin/vertx-web-kotlin-dsljson/gradlew.bat b/frameworks/Kotlin/vertx-web-kotlin-dsljson/gradlew.bat new file mode 100644 index 00000000000..9d21a21834d --- /dev/null +++ b/frameworks/Kotlin/vertx-web-kotlin-dsljson/gradlew.bat @@ -0,0 +1,94 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem +@rem SPDX-License-Identifier: Apache-2.0 +@rem + +@if "%DEBUG%"=="" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if %ERRORLEVEL% equ 0 goto execute + +echo. 1>&2 +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. 1>&2 +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if %ERRORLEVEL% equ 0 goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/frameworks/Kotlin/vertx-web-kotlin-dsljson/settings.gradle.kts b/frameworks/Kotlin/vertx-web-kotlin-dsljson/settings.gradle.kts new file mode 100644 index 00000000000..a5d0428ce6f --- /dev/null +++ b/frameworks/Kotlin/vertx-web-kotlin-dsljson/settings.gradle.kts @@ -0,0 +1 @@ +rootProject.name = "vertx-web-kotlin-dsljson-benchmark" diff --git a/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/App.kt b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/App.kt new file mode 100644 index 00000000000..03fb0ca2c04 --- /dev/null +++ b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/App.kt @@ -0,0 +1,50 @@ +package com.example.starter + +import com.example.starter.utils.PeriodicDateResolver +import com.example.starter.utils.block +import io.vertx.core.Vertx +import io.vertx.core.impl.cpu.CpuCoreSensor +import io.vertx.kotlin.core.deploymentOptionsOf +import io.vertx.kotlin.core.vertxOptionsOf +import kotlin.time.Duration.Companion.seconds +import org.apache.logging.log4j.kotlin.Logging + +object App : Logging { + private const val SERVER_NAME = "Vert.x-Web Benchmark" + + @JvmStatic + fun main(args: Array?) { + val numCores = CpuCoreSensor.availableProcessors() + + val vertx = Vertx.vertx( + vertxOptionsOf( + eventLoopPoolSize = numCores, + preferNativeTransport = true, + ) + ) + vertx.exceptionHandler { + logger.error(it) { "Vertx unexpected exception:" } + vertx.close().block(5.seconds) + } + + // Add the SIGINT handler + Runtime.getRuntime().addShutdownHook(Thread { + vertx.close().block(5.seconds) + }) + + // Initialize the periodic date resolver + PeriodicDateResolver.init(vertx) + + // Check the type of test that is being run + val hasDb = System.getProperty("tfb.hasDB")?.toBoolean() ?: false + + vertx.deployVerticle( + { if (hasDb) PostgresVerticle() else BasicVerticle() }, + deploymentOptionsOf( + instances = numCores, + ) + ) + + logger.info("$SERVER_NAME started.") + } +} \ No newline at end of file diff --git a/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/BasicVerticle.kt b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/BasicVerticle.kt new file mode 100644 index 00000000000..7870a146c78 --- /dev/null +++ b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/BasicVerticle.kt @@ -0,0 +1,56 @@ +package com.example.starter + +import com.example.starter.handlers.DefaultHandler +import com.example.starter.handlers.MessageHandler +import com.example.starter.io.JsonResource +import com.example.starter.utils.isConnectionReset +import io.vertx.core.AbstractVerticle +import io.vertx.core.Promise +import io.vertx.core.http.HttpServerOptions +import io.vertx.ext.web.Router +import org.apache.logging.log4j.kotlin.Logging + +class BasicVerticle : AbstractVerticle() { + override fun start(startPromise: Promise) { + val defaultHandler = DefaultHandler() + val messageHandler = MessageHandler() + + val router = Router.router(vertx) + + router + .get("/plaintext") + .handler(defaultHandler::plaintext) + + router + .get("/json") + .handler(messageHandler::readDefaultMessage) + + val server = vertx + .createHttpServer(HTTP_SERVER_OPTIONS) + .requestHandler(router) + .exceptionHandler { + if (it.isConnectionReset()) return@exceptionHandler + logger.error(it) { "Exception in HttpServer" } + } + + server + .listen() + .onSuccess { + logger.info { "HTTP server started on port 8080" } + startPromise.complete() + } + .onFailure { + logger.error(it.cause) { "Failed to start" } + startPromise.fail(it.cause) + } + } + + companion object : Logging { + private const val HTTP_SERVER_OPTIONS_RESOURCE = "http-server-options.json" + + private val HTTP_SERVER_OPTIONS: HttpServerOptions by lazy { + val json = JsonResource.of(HTTP_SERVER_OPTIONS_RESOURCE) + HttpServerOptions(json) + } + } +} diff --git a/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/PostgresVerticle.kt b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/PostgresVerticle.kt new file mode 100644 index 00000000000..43cba217ec0 --- /dev/null +++ b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/PostgresVerticle.kt @@ -0,0 +1,88 @@ +package com.example.starter + +import com.example.starter.db.FortuneRepository +import com.example.starter.db.WorldRepository +import com.example.starter.handlers.FortuneHandler +import com.example.starter.handlers.WorldHandler +import com.example.starter.io.JsonResource +import com.example.starter.utils.array +import com.example.starter.utils.isConnectionReset +import io.vertx.core.AbstractVerticle +import io.vertx.core.Future +import io.vertx.core.Promise +import io.vertx.core.http.HttpServerOptions +import io.vertx.ext.web.Router +import io.vertx.pgclient.PgConnectOptions +import io.vertx.pgclient.PgConnection +import org.apache.logging.log4j.kotlin.Logging + +class PostgresVerticle : AbstractVerticle() { + override fun start(startPromise: Promise) { + Future.all( + PgConnection.connect(vertx, PG_CONNECT_OPTIONS), + PgConnection.connect(vertx, PG_CONNECT_OPTIONS), + ) + .onSuccess { cf -> + val pool = cf.array() + + val fortuneHandler = FortuneHandler(FortuneRepository(pool)) + val worldHandler = WorldHandler(WorldRepository(pool)) + + val router = Router.router(vertx) + + router + .get("/fortunes") + .handler(fortuneHandler::templateFortunes) + + router + .get("/db") + .handler(worldHandler::readRandomWorld) + + router + .get("/queries") + .handler(worldHandler::readRandomWorlds) + + router + .get("/updates") + .handler(worldHandler::updateRandomWorlds) + + val server = vertx + .createHttpServer(HTTP_SERVER_OPTIONS) + .requestHandler(router) + .exceptionHandler { + if (it.isConnectionReset()) return@exceptionHandler + logger.error(it) { "Exception in HttpServer" } + } + + server + .listen() + .onSuccess { + logger.info { "HTTP server started on port 8080" } + startPromise.complete() + } + .onFailure { + logger.error(it) { "Failed to start" } + startPromise.fail(it) + } + } + .onFailure { + logger.error(it) { "Failed to start" } + startPromise.fail(it) + } + } + + companion object : Logging { + private const val HTTP_SERVER_OPTIONS_RESOURCE = "http-server-options.json" + private const val PG_CONNECT_OPTIONS_RESOURCE = "pg-connect-options.json" + + private val HTTP_SERVER_OPTIONS: HttpServerOptions by lazy { + val json = JsonResource.of(HTTP_SERVER_OPTIONS_RESOURCE) + HttpServerOptions(json) + } + + private val PG_CONNECT_OPTIONS: PgConnectOptions by lazy { + val json = JsonResource.of(PG_CONNECT_OPTIONS_RESOURCE) + PgConnectOptions(json) + } + } +} diff --git a/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/db/AbstractRepository.kt b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/db/AbstractRepository.kt new file mode 100644 index 00000000000..df665df0769 --- /dev/null +++ b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/db/AbstractRepository.kt @@ -0,0 +1,7 @@ +package com.example.starter.db + +import io.vertx.pgclient.PgConnection + +abstract class AbstractRepository( + protected val pool: Array +) \ No newline at end of file diff --git a/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/db/FortuneRepository.kt b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/db/FortuneRepository.kt new file mode 100644 index 00000000000..3bb95576a4d --- /dev/null +++ b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/db/FortuneRepository.kt @@ -0,0 +1,23 @@ +package com.example.starter.db + +import com.example.starter.models.Fortune +import com.example.starter.utils.mapToArray + +import io.vertx.core.Future +import io.vertx.pgclient.PgConnection +import io.vertx.sqlclient.Row + +class FortuneRepository(pool: Array) : AbstractRepository(pool) { + private val selectFortuneQuery = this.pool[0].preparedQuery(SELECT_FORTUNE_SQL) + + fun selectFortunes(): Future> = selectFortuneQuery + .execute() + .map { it.mapToArray(FortuneRepository::map) } + + companion object { + private const val SELECT_FORTUNE_SQL = "SELECT id, message FROM fortune" + + @Suppress("NOTHING_TO_INLINE") + private inline fun map(row: Row): Fortune = Fortune(row.getInteger(0), row.getString(1)) + } +} \ No newline at end of file diff --git a/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/db/WorldRepository.kt b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/db/WorldRepository.kt new file mode 100644 index 00000000000..734b486547a --- /dev/null +++ b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/db/WorldRepository.kt @@ -0,0 +1,84 @@ +package com.example.starter.db + +import com.example.starter.models.World +import io.vertx.core.Future +import io.vertx.core.Promise +import io.vertx.pgclient.PgConnection +import io.vertx.sqlclient.PreparedQuery +import io.vertx.sqlclient.Row +import io.vertx.sqlclient.RowSet +import io.vertx.sqlclient.Tuple +import io.vertx.sqlclient.impl.ArrayTuple +import io.vertx.sqlclient.impl.SqlClientInternal +import java.util.concurrent.ThreadLocalRandom +import java.util.concurrent.atomic.AtomicInteger + +@Suppress("NOTHING_TO_INLINE") +class WorldRepository(pool: Array) : AbstractRepository(pool) { + private val selectWorldQuery = this.pool[0].preparedQuery(SELECT_WORLD_SQL) + private val updateWorldQueries = generateQueries(this.pool[1]) + + fun selectRandomWorld(): Future = selectWorldQuery + .execute(Tuple.of(randomWorld())) + .map { map(it.iterator().next()) } + + fun selectRandomWorlds(numWorlds: Int): Future> { + val promise = Promise.promise>() + val arr = arrayOfNulls(numWorlds) + val count = AtomicInteger(0) + (this.pool[0] as SqlClientInternal).group { c -> + repeat(numWorlds) { + c.preparedQuery(SELECT_WORLD_SQL).execute(Tuple.of(randomWorld())) { ar -> + val index = count.getAndIncrement() + arr[index] = map(ar.result().iterator().next()) + if (index == numWorlds - 1) { + promise.complete(arr as Array) + } + } + } + } + return promise.future() + } + + fun updateRandomWorlds(numWorlds: Int): Future> = selectRandomWorlds(numWorlds) + .flatMap { worlds -> + val params = ArrayTuple(worlds.size * 3) + worlds.forEach { + it.randomNumber = randomWorld() + params.addValue(it.id) + params.addValue(it.randomNumber) + } + worlds.forEach { + params.addValue(it.id) + } + updateWorldQueries[numWorlds - 1].execute(params).map { worlds } + } + + companion object { + private const val SELECT_WORLD_SQL = "SELECT id, randomnumber FROM world WHERE id = $1" + + private inline fun randomWorld(): Int = 1 + ThreadLocalRandom.current().nextInt(10000) + private inline fun map(row: Row): World = World(row.getInteger(0), row.getInteger(1)) + + private fun generateQueries(conn: PgConnection): Array>> { + val arr = arrayOfNulls>>(500) + for (num in 1..500) { + var paramIndex = 1 + val sb = StringBuilder() + sb.append("UPDATE world SET randomnumber = CASE id ") + for (i in 1..num) { + sb.append("WHEN \$$paramIndex THEN \$${paramIndex + 1} ") + paramIndex += 2 + } + sb.append("ELSE randomnumber END WHERE id IN (") + for (i in 1..num) { + sb.append("\$$paramIndex,") + paramIndex += 1 + } + sb[sb.length - 1] = ')' + arr[num - 1] = conn.preparedQuery(sb.toString()) + } + return arr as Array>> + } + } +} diff --git a/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/handlers/AbstractHandler.kt b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/handlers/AbstractHandler.kt new file mode 100644 index 00000000000..cb29d630167 --- /dev/null +++ b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/handlers/AbstractHandler.kt @@ -0,0 +1,57 @@ +package com.example.starter.handlers + +import com.example.starter.utils.PeriodicDateResolver +import io.vertx.core.AsyncResult +import io.vertx.core.Handler +import io.vertx.core.MultiMap +import io.vertx.core.http.HttpHeaders +import io.vertx.core.http.HttpServerResponse +import io.vertx.ext.web.RoutingContext + +@Suppress("NOTHING_TO_INLINE") +abstract class AbstractHandler { + protected companion object { + val NULL_HANDLER: Handler>? = null + + const val SOMETHING_WENT_WRONG = "Something went wrong" + + // Headers + val SERVER: CharSequence = HttpHeaders.createOptimized("Vert.x-Web") + val APPLICATION_JSON: CharSequence = HttpHeaders.createOptimized("application/json") + val TEXT_PLAIN: CharSequence = HttpHeaders.createOptimized("text/plain") + val TEXT_HTML: CharSequence = HttpHeaders.createOptimized("text/html; charset=utf-8") + + inline fun MultiMap.common(): MultiMap = this + .add(HttpHeaders.SERVER, SERVER) + .add(HttpHeaders.DATE, PeriodicDateResolver.current) + + inline fun RoutingContext.json(): HttpServerResponse { + val response = this.response() + val headers = response.headers() + headers + .common() + .add(HttpHeaders.CONTENT_TYPE, APPLICATION_JSON) + return response + } + + inline fun RoutingContext.text(): HttpServerResponse { + val response = this.response() + val headers = response.headers() + headers + .common() + .add(HttpHeaders.CONTENT_TYPE, TEXT_PLAIN) + return response + } + + inline fun RoutingContext.html(): HttpServerResponse { + val response = this.response() + val headers = response.headers() + headers + .common() + .add(HttpHeaders.CONTENT_TYPE, TEXT_HTML) + return response + } + + inline fun RoutingContext.error(): Unit = this.text().end(SOMETHING_WENT_WRONG, NULL_HANDLER) + } +} \ No newline at end of file diff --git a/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/handlers/DefaultHandler.kt b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/handlers/DefaultHandler.kt new file mode 100644 index 00000000000..8311474177e --- /dev/null +++ b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/handlers/DefaultHandler.kt @@ -0,0 +1,15 @@ +package com.example.starter.handlers + +import io.vertx.core.buffer.Buffer +import io.vertx.ext.web.RoutingContext + +class DefaultHandler : AbstractHandler() { + fun plaintext(ctx: RoutingContext) { + ctx.text().end(MESSAGE_BUFFER, NULL_HANDLER) + } + + companion object { + private const val MESSAGE = "Hello, World!" + private val MESSAGE_BUFFER = Buffer.buffer(MESSAGE, "UTF-8") + } +} diff --git a/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/handlers/FortuneHandler.kt b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/handlers/FortuneHandler.kt new file mode 100644 index 00000000000..5e60c04cfeb --- /dev/null +++ b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/handlers/FortuneHandler.kt @@ -0,0 +1,57 @@ +package com.example.starter.handlers + +import com.example.starter.db.FortuneRepository +import com.example.starter.models.Fortune +import htmlflow.HtmlFlow +import htmlflow.HtmlView +import io.vertx.ext.web.RoutingContext +import org.apache.logging.log4j.kotlin.Logging + +class FortuneHandler(private val repository: FortuneRepository) : AbstractHandler() { + fun templateFortunes(ctx: RoutingContext) { + repository + .selectFortunes() + .onSuccess { + val updatedFortunes = it.plus(Fortune(0, "Additional fortune added at request time.")) + updatedFortunes.sort() + ctx.html().end(TEMPLATE.render(updatedFortunes), NULL_HANDLER) + } + .onFailure { + logger.error(it) { SOMETHING_WENT_WRONG } + ctx.error() + } + } + + companion object : Logging { + private val TEMPLATE: HtmlView = HtmlFlow + .view { page -> + page + .html() + .head() + .title() + .text("Fortunes") + .`__`() // title + .`__`() // head + .body() + .table() + .tr() + .th().text("id").`__`() + .th().text("message").`__`() + .`__`() // tr + .dynamic> { container, fortunes -> + fortunes.forEach { + container + .tr() + .td().text(it.id.toString()).`__`() + .td().text(it.message).`__`() + .`__`() // tr + } + } + .`__`() // table + .`__`() // body + .`__`() // html + } + .setIndented(false) + .threadSafe() + } +} \ No newline at end of file diff --git a/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/handlers/MessageHandler.kt b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/handlers/MessageHandler.kt new file mode 100644 index 00000000000..1fa432ef313 --- /dev/null +++ b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/handlers/MessageHandler.kt @@ -0,0 +1,15 @@ +package com.example.starter.handlers + +import com.example.starter.models.Message +import com.example.starter.utils.serialize +import io.vertx.ext.web.RoutingContext + +class MessageHandler : AbstractHandler() { + fun readDefaultMessage(ctx: RoutingContext) { + ctx.json().end(DEFAULT_MESSAGE.serialize(), NULL_HANDLER) + } + + companion object { + private val DEFAULT_MESSAGE = Message("Hello, World!") + } +} diff --git a/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/handlers/WorldHandler.kt b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/handlers/WorldHandler.kt new file mode 100644 index 00000000000..1226361d71b --- /dev/null +++ b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/handlers/WorldHandler.kt @@ -0,0 +1,56 @@ +package com.example.starter.handlers + +import com.example.starter.db.WorldRepository +import com.example.starter.utils.serialize +import io.vertx.ext.web.RoutingContext +import org.apache.logging.log4j.kotlin.Logging + +class WorldHandler(private val repository: WorldRepository) : AbstractHandler() { + fun readRandomWorld(ctx: RoutingContext) { + repository + .selectRandomWorld() + .onSuccess { + ctx.json().end(it.serialize(), NULL_HANDLER) + } + .onFailure { + logger.error(it) { SOMETHING_WENT_WRONG } + ctx.error() + } + } + + fun readRandomWorlds(ctx: RoutingContext) { + val queries = ctx.queries() + repository + .selectRandomWorlds(queries) + .onSuccess { + ctx.json().end(it.serialize(), NULL_HANDLER) + } + .onFailure { + logger.error(it) { SOMETHING_WENT_WRONG } + ctx.error() + } + } + + fun updateRandomWorlds(ctx: RoutingContext) { + val queries = ctx.queries() + repository + .updateRandomWorlds(queries) + .onSuccess { + ctx.json().end(it.serialize(), NULL_HANDLER) + } + .onFailure { + logger.error(it) { SOMETHING_WENT_WRONG } + ctx.error() + } + } + + companion object : Logging { + private const val QUERIES_PARAM_NAME = "queries" + + @Suppress("NOTHING_TO_INLINE") + private inline fun RoutingContext.queries(): Int { + val queriesParam = this.request().getParam(QUERIES_PARAM_NAME) + return queriesParam?.toIntOrNull()?.coerceIn(1, 500) ?: 1 + } + } +} \ No newline at end of file diff --git a/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/io/BufferOutputStream.kt b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/io/BufferOutputStream.kt new file mode 100644 index 00000000000..d82b31fb6ee --- /dev/null +++ b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/io/BufferOutputStream.kt @@ -0,0 +1,362 @@ +package com.example.starter.io + +import io.netty.buffer.ByteBuf +import io.vertx.core.buffer.Buffer +import io.vertx.core.json.JsonArray +import io.vertx.core.json.JsonObject +import java.io.IOException +import java.io.OutputStream +import java.nio.ByteBuffer +import java.nio.charset.Charset + +class BufferOutputStream(initialSizeHint: Int = 0) : Buffer, OutputStream() { + private val buffer: Buffer = Buffer.buffer(initialSizeHint) + + @Throws(IOException::class) + override fun write(b: Int) { + buffer.appendByte(b.toByte()) + } + + @Throws(IOException::class) + override fun write(bytes: ByteArray) { + buffer.appendBytes(bytes) + } + + @Throws(IOException::class) + override fun write(bytes: ByteArray, offset: Int, len: Int) { + buffer.appendBytes(bytes, offset, len) + } + + override fun toString(enc: String?): String { + return buffer.toString(enc) + } + + override fun toString(enc: Charset?): String { + return buffer.toString(enc) + } + + override fun writeToBuffer(other: Buffer?) { + buffer.writeToBuffer(other) + } + + override fun readFromBuffer(pos: Int, other: Buffer?): Int { + return buffer.readFromBuffer(pos, other) + } + + override fun copy(): Buffer { + return buffer.copy() + } + + override fun toJsonObject(): JsonObject { + return buffer.toJsonObject() + } + + override fun toJsonArray(): JsonArray { + return buffer.toJsonArray() + } + + override fun getByte(pos: Int): Byte { + return buffer.getByte(pos) + } + + override fun getUnsignedByte(pos: Int): Short { + return buffer.getUnsignedByte(pos) + } + + override fun getInt(pos: Int): Int { + return buffer.getInt(pos) + } + + override fun getIntLE(pos: Int): Int { + return buffer.getIntLE(pos) + } + + override fun getUnsignedInt(pos: Int): Long { + return buffer.getUnsignedInt(pos) + } + + override fun getUnsignedIntLE(pos: Int): Long { + return buffer.getUnsignedIntLE(pos) + } + + override fun getLong(pos: Int): Long { + return buffer.getLong(pos) + } + + override fun getLongLE(pos: Int): Long { + return buffer.getLongLE(pos) + } + + override fun getDouble(pos: Int): Double { + return buffer.getDouble(pos) + } + + override fun getFloat(pos: Int): Float { + return buffer.getFloat(pos) + } + + override fun getShort(pos: Int): Short { + return buffer.getShort(pos) + } + + override fun getShortLE(pos: Int): Short { + return buffer.getShortLE(pos) + } + + override fun getUnsignedShort(pos: Int): Int { + return buffer.getUnsignedShort(pos) + } + + override fun getUnsignedShortLE(pos: Int): Int { + return buffer.getUnsignedShortLE(pos) + } + + override fun getMedium(pos: Int): Int { + return buffer.getMedium(pos) + } + + override fun getMediumLE(pos: Int): Int { + return buffer.getMediumLE(pos) + } + + override fun getUnsignedMedium(pos: Int): Int { + return buffer.getUnsignedMedium(pos) + } + + override fun getUnsignedMediumLE(pos: Int): Int { + return buffer.getUnsignedMediumLE(pos) + } + + override fun getBytes(): ByteArray { + return buffer.bytes + } + + override fun getBytes(start: Int, end: Int): ByteArray { + return buffer.getBytes(start, end) + } + + override fun getBytes(dst: ByteArray?): Buffer { + return buffer.getBytes(dst) + } + + override fun getBytes(dst: ByteArray?, dstIndex: Int): Buffer { + return buffer.getBytes(dst, dstIndex) + } + + override fun getBytes(start: Int, end: Int, dst: ByteArray?): Buffer { + return buffer.getBytes(start, end, dst) + } + + override fun getBytes(start: Int, end: Int, dst: ByteArray?, dstIndex: Int): Buffer { + return buffer.getBytes(start, end, dst, dstIndex) + } + + override fun getBuffer(start: Int, end: Int): Buffer { + return buffer.getBuffer(start, end) + } + + override fun getString(start: Int, end: Int, enc: String?): String { + return buffer.getString(start, end, enc) + } + + override fun getString(start: Int, end: Int): String { + return buffer.getString(start, end) + } + + override fun appendBuffer(buff: Buffer?): Buffer { + return buffer.appendBuffer(buff) + } + + override fun appendBuffer(buff: Buffer?, offset: Int, len: Int): Buffer { + return buffer.appendBuffer(buff, offset, len) + } + + override fun appendBytes(bytes: ByteArray?): Buffer { + return buffer.appendBytes(bytes) + } + + override fun appendBytes(bytes: ByteArray?, offset: Int, len: Int): Buffer { + return buffer.appendBytes(bytes, offset, len) + } + + override fun appendByte(b: Byte): Buffer { + return buffer.appendByte(b) + } + + override fun appendUnsignedByte(b: Short): Buffer { + return buffer.appendUnsignedByte(b) + } + + override fun appendInt(i: Int): Buffer { + return buffer.appendInt(i) + } + + override fun appendIntLE(i: Int): Buffer { + return buffer.appendIntLE(i) + } + + override fun appendUnsignedInt(i: Long): Buffer { + return buffer.appendUnsignedInt(i) + } + + override fun appendUnsignedIntLE(i: Long): Buffer { + return buffer.appendUnsignedIntLE(i) + } + + override fun appendMedium(i: Int): Buffer { + return buffer.appendMedium(i) + } + + override fun appendMediumLE(i: Int): Buffer { + return buffer.appendMediumLE(i) + } + + override fun appendLong(l: Long): Buffer { + return buffer.appendLong(l) + } + + override fun appendLongLE(l: Long): Buffer { + return buffer.appendLongLE(l) + } + + override fun appendShort(s: Short): Buffer { + return buffer.appendShort(s) + } + + override fun appendShortLE(s: Short): Buffer { + return buffer.appendShortLE(s) + } + + override fun appendUnsignedShort(s: Int): Buffer { + return buffer.appendUnsignedShort(s) + } + + override fun appendUnsignedShortLE(s: Int): Buffer { + return buffer.appendUnsignedShortLE(s) + } + + override fun appendFloat(f: Float): Buffer { + return buffer.appendFloat(f) + } + + override fun appendDouble(d: Double): Buffer { + return buffer.appendDouble(d) + } + + override fun appendString(str: String?, enc: String?): Buffer { + return buffer.appendString(str, enc) + } + + override fun appendString(str: String?): Buffer { + return buffer.appendString(str) + } + + override fun setByte(pos: Int, b: Byte): Buffer { + return buffer.setByte(pos, b) + } + + override fun setUnsignedByte(pos: Int, b: Short): Buffer { + return buffer.setUnsignedByte(pos, b) + } + + override fun setInt(pos: Int, i: Int): Buffer { + return buffer.setInt(pos, i) + } + + override fun setIntLE(pos: Int, i: Int): Buffer { + return buffer.setIntLE(pos, i) + } + + override fun setUnsignedInt(pos: Int, i: Long): Buffer { + return buffer.setUnsignedInt(pos, i) + } + + override fun setUnsignedIntLE(pos: Int, i: Long): Buffer { + return buffer.setUnsignedIntLE(pos, i) + } + + override fun setMedium(pos: Int, i: Int): Buffer { + return buffer.setMedium(pos, i) + } + + override fun setMediumLE(pos: Int, i: Int): Buffer { + return buffer.setMediumLE(pos, i) + } + + override fun setLong(pos: Int, l: Long): Buffer { + return buffer.setLong(pos, l) + } + + override fun setLongLE(pos: Int, l: Long): Buffer { + return buffer.setLongLE(pos, l) + } + + override fun setDouble(pos: Int, d: Double): Buffer { + return buffer.setDouble(pos, d) + } + + override fun setFloat(pos: Int, f: Float): Buffer { + return buffer.setFloat(pos, f) + } + + override fun setShort(pos: Int, s: Short): Buffer { + return buffer.setShort(pos, s) + } + + override fun setShortLE(pos: Int, s: Short): Buffer { + return buffer.setShortLE(pos, s) + } + + override fun setUnsignedShort(pos: Int, s: Int): Buffer { + return buffer.setUnsignedShort(pos, s) + } + + override fun setUnsignedShortLE(pos: Int, s: Int): Buffer { + return buffer.setUnsignedShortLE(pos, s) + } + + override fun setBuffer(pos: Int, b: Buffer?): Buffer { + return buffer.setBuffer(pos, b) + } + + override fun setBuffer(pos: Int, b: Buffer?, offset: Int, len: Int): Buffer { + return buffer.setBuffer(pos, b, offset, len) + } + + override fun setBytes(pos: Int, b: ByteBuffer?): Buffer { + return buffer.setBytes(pos, b) + } + + override fun setBytes(pos: Int, b: ByteArray?): Buffer { + return buffer.setBytes(pos, b) + } + + override fun setBytes(pos: Int, b: ByteArray?, offset: Int, len: Int): Buffer { + return buffer.setBytes(pos, b, offset, len) + } + + override fun setString(pos: Int, str: String?): Buffer { + return buffer.setString(pos, str) + } + + override fun setString(pos: Int, str: String?, enc: String?): Buffer { + return buffer.setString(pos, str, enc) + } + + override fun length(): Int { + return buffer.length() + } + + override fun slice(): Buffer { + return buffer.slice() + } + + override fun slice(start: Int, end: Int): Buffer { + return buffer.slice(start, end) + } + + @Deprecated("Deprecated in Java") + override fun getByteBuf(): ByteBuf { + return buffer.byteBuf + } +} \ No newline at end of file diff --git a/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/io/JsonResource.kt b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/io/JsonResource.kt new file mode 100644 index 00000000000..fbf355e66a9 --- /dev/null +++ b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/io/JsonResource.kt @@ -0,0 +1,15 @@ +package com.example.starter.io + +import io.vertx.core.json.JsonObject + +object JsonResource { + fun of(resource: String): JsonObject { + val classLoader = ClassLoader.getSystemClassLoader() + classLoader.getResourceAsStream(resource)?.use { input -> + val output = BufferOutputStream() + output.write(input.readAllBytes()) + return output.toJsonObject() + } + throw IllegalStateException("$resource not found") + } +} diff --git a/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/models/Fortune.kt b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/models/Fortune.kt new file mode 100644 index 00000000000..4b832526750 --- /dev/null +++ b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/models/Fortune.kt @@ -0,0 +1,14 @@ +package com.example.starter.models + +import com.dslplatform.json.CompiledJson +import com.dslplatform.json.JsonAttribute + +@CompiledJson +class Fortune( + @JsonAttribute(nullable = false) val id: Int, + @JsonAttribute(nullable = false) val message: String +) : Comparable { + override fun compareTo(other: Fortune): Int { + return message.compareTo(other.message) + } +} diff --git a/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/models/Message.kt b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/models/Message.kt new file mode 100644 index 00000000000..eb7fc6250a3 --- /dev/null +++ b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/models/Message.kt @@ -0,0 +1,7 @@ +package com.example.starter.models + +import com.dslplatform.json.CompiledJson +import com.dslplatform.json.JsonAttribute + +@CompiledJson +class Message(@JsonAttribute(nullable = false) val message: String) diff --git a/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/models/World.kt b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/models/World.kt new file mode 100644 index 00000000000..5011a2bb2e0 --- /dev/null +++ b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/models/World.kt @@ -0,0 +1,14 @@ +package com.example.starter.models + +import com.dslplatform.json.CompiledJson +import com.dslplatform.json.JsonAttribute + +@CompiledJson +class World( + @JsonAttribute(nullable = false) val id: Int, + @JsonAttribute(nullable = false) var randomNumber: Int +) : Comparable { + override fun compareTo(other: World): Int { + return id.compareTo(other.id) + } +} diff --git a/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/utils/FutureExtensions.kt b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/utils/FutureExtensions.kt new file mode 100644 index 00000000000..03d5a018575 --- /dev/null +++ b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/utils/FutureExtensions.kt @@ -0,0 +1,14 @@ +package com.example.starter.utils + +import io.vertx.core.CompositeFuture +import io.vertx.core.Future +import java.util.concurrent.TimeUnit +import kotlin.time.Duration + +inline fun CompositeFuture.array(): Array = Array(this.size()) { this.resultAt(it) } + +@Suppress("NOTHING_TO_INLINE") +inline fun > T.block(duration: Duration): R = this + .toCompletionStage() + .toCompletableFuture() + .get(duration.inWholeMilliseconds, TimeUnit.MILLISECONDS) \ No newline at end of file diff --git a/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/utils/JsonExtensions.kt b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/utils/JsonExtensions.kt new file mode 100644 index 00000000000..87c965ca9b7 --- /dev/null +++ b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/utils/JsonExtensions.kt @@ -0,0 +1,19 @@ +package com.example.starter.utils + +import com.dslplatform.json.DslJson +import com.dslplatform.json.runtime.Settings +import com.example.starter.io.BufferOutputStream +import io.vertx.core.buffer.Buffer + +val DSL_JSON: DslJson = DslJson( + Settings.withRuntime() + .includeServiceLoader() + .useStringValuesCache(DslJson.SimpleStringCache()) +) + +@Suppress("NOTHING_TO_INLINE") +inline fun T.serialize(initialSizeHint: Int = 0): Buffer { + val output = BufferOutputStream(initialSizeHint) + DSL_JSON.serialize(this, output) + return output +} \ No newline at end of file diff --git a/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/utils/PeriodicDateResolver.kt b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/utils/PeriodicDateResolver.kt new file mode 100644 index 00000000000..2e29e784914 --- /dev/null +++ b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/utils/PeriodicDateResolver.kt @@ -0,0 +1,16 @@ +package com.example.starter.utils + +import io.vertx.core.Vertx +import java.time.ZonedDateTime +import java.time.format.DateTimeFormatter + +object PeriodicDateResolver { + var current: String = next() + + fun init(vertx: Vertx) { + vertx.setPeriodic(1000L) { current = next() } + } + + @Suppress("NOTHING_TO_INLINE") + private inline fun next(): String = DateTimeFormatter.RFC_1123_DATE_TIME.format(ZonedDateTime.now()) +} \ No newline at end of file diff --git a/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/utils/RowSetExtensions.kt b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/utils/RowSetExtensions.kt new file mode 100644 index 00000000000..c968777ff77 --- /dev/null +++ b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/utils/RowSetExtensions.kt @@ -0,0 +1,14 @@ +package com.example.starter.utils + +import io.vertx.sqlclient.Row +import io.vertx.sqlclient.RowSet + +// This extension relies on the assumption the mapper never returns null, as it is defined. Otherwise, +// we prevent the overhead from having to do another iteration over the loop for a `filterNotNull` check. +inline fun RowSet.mapToArray(mapper: (Row) -> U): Array { + val arr = arrayOfNulls(this.size()) + val iterator = this.iterator() + var index = 0 + while (iterator.hasNext()) arr[index++] = mapper(iterator.next()) + return arr as Array +} \ No newline at end of file diff --git a/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/utils/ThrowableExtensions.kt b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/utils/ThrowableExtensions.kt new file mode 100644 index 00000000000..044d24b06ab --- /dev/null +++ b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/utils/ThrowableExtensions.kt @@ -0,0 +1,12 @@ +package com.example.starter.utils + +import io.netty.channel.unix.Errors +import io.netty.channel.unix.Errors.NativeIoException +import java.net.SocketException + +const val CONNECTION_RESET_MESSAGE = "Connection reset" + +fun Throwable.isConnectionReset(): Boolean { + return (this is NativeIoException && this.expectedErr() == Errors.ERRNO_ECONNRESET_NEGATIVE) + || (this is SocketException && this.message == CONNECTION_RESET_MESSAGE) +} \ No newline at end of file diff --git a/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/resources/http-server-options.json b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/resources/http-server-options.json new file mode 100644 index 00000000000..a790bc93043 --- /dev/null +++ b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/resources/http-server-options.json @@ -0,0 +1,6 @@ +{ + "port": 8080, + "tcpFastOpen": true, + "receiveBufferSize": 262144, + "sendBufferSize": 262144 +} \ No newline at end of file diff --git a/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/resources/log4j2.xml b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/resources/log4j2.xml new file mode 100644 index 00000000000..ebe0ad3cb74 --- /dev/null +++ b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/resources/log4j2.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/resources/pg-connect-options.json b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/resources/pg-connect-options.json new file mode 100644 index 00000000000..a145a0a51c5 --- /dev/null +++ b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/resources/pg-connect-options.json @@ -0,0 +1,15 @@ +{ + "user": "benchmarkdbuser", + "password": "benchmarkdbpass", + "host": "tfb-database", + "port": 5432, + "database": "hello_world", + "cachePreparedStatements": true, + "preparedStatementCacheMaxSize": 512, + "preparedStatementCacheSqlLimit": 2048, + "tcpKeepAlive": true, + "tcpFastOpen": true, + "pipeliningLimit": 100000, + "receiveBufferSize": 262144, + "sendBufferSize": 262144 +} \ No newline at end of file diff --git a/frameworks/Kotlin/vertx-web-kotlin-dsljson/vertx-web-kotlin-dsljson-postgresql.dockerfile b/frameworks/Kotlin/vertx-web-kotlin-dsljson/vertx-web-kotlin-dsljson-postgresql.dockerfile new file mode 100644 index 00000000000..0ef28c410d9 --- /dev/null +++ b/frameworks/Kotlin/vertx-web-kotlin-dsljson/vertx-web-kotlin-dsljson-postgresql.dockerfile @@ -0,0 +1,37 @@ +FROM gradle:8.9-jdk21 as gradle + +WORKDIR /vertx-web-kotlin-dsljson + +COPY src src +COPY build.gradle.kts build.gradle.kts +COPY gradle.properties gradle.properties +COPY settings.gradle.kts settings.gradle.kts + +RUN gradle shadowJar + +EXPOSE 8080 + +CMD java \ + -server \ + -Xms2G \ + -Xmx2G \ + -XX:+AlwaysPreTouch \ + -XX:+UseParallelGC \ + -XX:InitialCodeCacheSize=512m \ + -XX:ReservedCodeCacheSize=512m \ + -XX:MaxInlineLevel=20 \ + -XX:+UseNUMA \ + -Dvertx.disableMetrics=true \ + -Dvertx.disableH2c=true \ + -Dvertx.disableWebsockets=true \ + -Dvertx.flashPolicyHandler=false \ + -Dvertx.threadChecks=false \ + -Dvertx.disableContextTimings=true \ + -Dvertx.disableTCCL=true \ + -Dvertx.disableHttpHeadersValidation=true \ + -Dlog4j2.contextSelector=org.apache.logging.log4j.core.async.AsyncLoggerContextSelector \ + -Dio.netty.buffer.checkBounds=false \ + -Dio.netty.buffer.checkAccessible=false \ + -Dtfb.hasDB=true \ + -jar \ + build/libs/vertx-web-kotlin-dsljson-benchmark-1.0.0-SNAPSHOT-fat.jar diff --git a/frameworks/Kotlin/vertx-web-kotlin-dsljson/vertx-web-kotlin-dsljson.dockerfile b/frameworks/Kotlin/vertx-web-kotlin-dsljson/vertx-web-kotlin-dsljson.dockerfile new file mode 100644 index 00000000000..a4a1c142cf5 --- /dev/null +++ b/frameworks/Kotlin/vertx-web-kotlin-dsljson/vertx-web-kotlin-dsljson.dockerfile @@ -0,0 +1,37 @@ +FROM gradle:8.9-jdk21 as gradle + +WORKDIR /vertx-web-kotlin-dsljson + +COPY src src +COPY build.gradle.kts build.gradle.kts +COPY gradle.properties gradle.properties +COPY settings.gradle.kts settings.gradle.kts + +RUN gradle shadowJar + +EXPOSE 8080 + +CMD java \ + -server \ + -Xms2G \ + -Xmx2G \ + -XX:+AlwaysPreTouch \ + -XX:+UseParallelGC \ + -XX:InitialCodeCacheSize=512m \ + -XX:ReservedCodeCacheSize=512m \ + -XX:MaxInlineLevel=20 \ + -XX:+UseNUMA \ + -Dvertx.disableMetrics=true \ + -Dvertx.disableH2c=true \ + -Dvertx.disableWebsockets=true \ + -Dvertx.flashPolicyHandler=false \ + -Dvertx.threadChecks=false \ + -Dvertx.disableContextTimings=true \ + -Dvertx.disableTCCL=true \ + -Dvertx.disableHttpHeadersValidation=true \ + -Dlog4j2.contextSelector=org.apache.logging.log4j.core.async.AsyncLoggerContextSelector \ + -Dio.netty.buffer.checkBounds=false \ + -Dio.netty.buffer.checkAccessible=false \ + -Dtfb.hasDB=false \ + -jar \ + build/libs/vertx-web-kotlin-dsljson-benchmark-1.0.0-SNAPSHOT-fat.jar From 64fd93c0849d6ecb869b7e427533d160cc5165f5 Mon Sep 17 00:00:00 2001 From: Yan Kun Date: Sat, 3 Aug 2024 00:00:17 +0800 Subject: [PATCH 056/204] [Scala/otavia] Add new framework otavia: Your shiny new IO & Actor programming model! (#9158) --- frameworks/Scala/otavia/.mill-version | 1 + frameworks/Scala/otavia/.scalafmt.conf | 16 ++ frameworks/Scala/otavia/README.MD | 13 ++ .../src/app/controller/DBController.scala | 106 ++++++++++ .../app/controller/FortuneController.scala | 41 ++++ .../benchmark/src/app/model/Fortune.scala | 7 + .../benchmark/src/app/model/Message.scala | 5 + .../benchmark/src/app/model/World.scala | 8 + .../otavia/benchmark/src/app/startup.scala | 70 +++++++ .../src/app/util/FortunesRender.scala | 64 ++++++ frameworks/Scala/otavia/benchmark_config.json | 53 +++++ frameworks/Scala/otavia/build.sc | 15 ++ frameworks/Scala/otavia/config.toml | 36 ++++ frameworks/Scala/otavia/millw | 194 ++++++++++++++++++ frameworks/Scala/otavia/millw.bat | 173 ++++++++++++++++ .../Scala/otavia/otavia-reserve.dockerfile | 15 ++ frameworks/Scala/otavia/otavia.dockerfile | 15 ++ 17 files changed, 832 insertions(+) create mode 100644 frameworks/Scala/otavia/.mill-version create mode 100644 frameworks/Scala/otavia/.scalafmt.conf create mode 100644 frameworks/Scala/otavia/README.MD create mode 100644 frameworks/Scala/otavia/benchmark/src/app/controller/DBController.scala create mode 100644 frameworks/Scala/otavia/benchmark/src/app/controller/FortuneController.scala create mode 100644 frameworks/Scala/otavia/benchmark/src/app/model/Fortune.scala create mode 100644 frameworks/Scala/otavia/benchmark/src/app/model/Message.scala create mode 100644 frameworks/Scala/otavia/benchmark/src/app/model/World.scala create mode 100644 frameworks/Scala/otavia/benchmark/src/app/startup.scala create mode 100644 frameworks/Scala/otavia/benchmark/src/app/util/FortunesRender.scala create mode 100644 frameworks/Scala/otavia/benchmark_config.json create mode 100644 frameworks/Scala/otavia/build.sc create mode 100644 frameworks/Scala/otavia/config.toml create mode 100644 frameworks/Scala/otavia/millw create mode 100644 frameworks/Scala/otavia/millw.bat create mode 100644 frameworks/Scala/otavia/otavia-reserve.dockerfile create mode 100644 frameworks/Scala/otavia/otavia.dockerfile diff --git a/frameworks/Scala/otavia/.mill-version b/frameworks/Scala/otavia/.mill-version new file mode 100644 index 00000000000..772c67a500f --- /dev/null +++ b/frameworks/Scala/otavia/.mill-version @@ -0,0 +1 @@ +0.11.8 \ No newline at end of file diff --git a/frameworks/Scala/otavia/.scalafmt.conf b/frameworks/Scala/otavia/.scalafmt.conf new file mode 100644 index 00000000000..ff856188419 --- /dev/null +++ b/frameworks/Scala/otavia/.scalafmt.conf @@ -0,0 +1,16 @@ +version = "3.5.3" + +runner.dialect = scala3 +maxColumn = 120 +docstrings.blankFirstLine = no +docstrings.style = AsteriskSpace +docstrings.removeEmpty = true +docstrings.oneline = fold +docstrings.wrap = yes +docstrings.wrapMaxColumn = 120 +docstrings.forceBlankLineBefore = true +align.preset = more + +indent.main = 4 + +newlines.topLevelBodyIfMinStatements = [before,after] \ No newline at end of file diff --git a/frameworks/Scala/otavia/README.MD b/frameworks/Scala/otavia/README.MD new file mode 100644 index 00000000000..0ea11222811 --- /dev/null +++ b/frameworks/Scala/otavia/README.MD @@ -0,0 +1,13 @@ +## Introduction + +[GitHub - otavia-projects/otavia : Your shiny new IO & Actor programming model!](https://github.com/otavia-projects/otavia) + +`otavia` is an IO and Actor programming model power by Scala 3, it provides a toolkit to make writing high-performance +concurrent programs more easily. + +You can get a quick overview of the basic usage and core design of `otavia` in the following documentation: + +- [Quick Start](https://github.com/otavia-projects/otavia/blob/main/docs/_docs/quick_start.md) +- [Core Concepts and Design](https://github.com/otavia-projects/otavia/blob/main/docs/_docs/core_concept.md) + +More document can be found at [website](https://otavia.cc/home.html) \ No newline at end of file diff --git a/frameworks/Scala/otavia/benchmark/src/app/controller/DBController.scala b/frameworks/Scala/otavia/benchmark/src/app/controller/DBController.scala new file mode 100644 index 00000000000..6b54504aecc --- /dev/null +++ b/frameworks/Scala/otavia/benchmark/src/app/controller/DBController.scala @@ -0,0 +1,106 @@ +package app.controller + +import app.controller.DBController.* +import app.model.World +import cc.otavia.core.actor.{MessageOf, StateActor} +import cc.otavia.core.address.Address +import cc.otavia.core.message.{Ask, Reply} +import cc.otavia.core.stack.helper.{FutureState, FuturesState, StartState} +import cc.otavia.core.stack.{AskStack, StackState, StackYield} +import cc.otavia.http.server.{HttpRequest, HttpResponse} +import cc.otavia.sql.Connection +import cc.otavia.sql.Statement.{ModifyRows, PrepareQuery} + +import java.util.SplittableRandom + +class DBController extends StateActor[REQ] { + + private var connection: Address[MessageOf[Connection]] = _ + + private val random = new SplittableRandom() + + override protected def afterMount(): Unit = connection = autowire[Connection]() + + override protected def resumeAsk(stack: AskStack[REQ & Ask[? <: Reply]]): StackYield = + stack match + case stack: AskStack[SingleQueryRequest] if stack.ask.isInstanceOf[SingleQueryRequest] => + handleSingleQuery(stack) + case stack: AskStack[MultipleQueryRequest] if stack.ask.isInstanceOf[MultipleQueryRequest] => + handleMultipleQuery(stack) + case stack: AskStack[UpdateRequest] if stack.ask.isInstanceOf[UpdateRequest] => + handleUpdateQuery(stack) + + // Test 2: Single database query + private def handleSingleQuery(stack: AskStack[SingleQueryRequest]): StackYield = { + stack.state match + case _: StartState => + val state = FutureState[World]() + connection.ask(PrepareQuery.fetchOne[World](SELECT_WORLD, Tuple1(randomWorld())), state.future) + stack.suspend(state) + case state: FutureState[World] => + stack.`return`(state.future.getNow) + } + + // Test 3: Multiple database queries + private def handleMultipleQuery(stack: AskStack[MultipleQueryRequest]): StackYield = { + stack.state match + case _: StartState => + stack.suspend(selectWorlds(normalizeQueries(stack.ask.params))) + case state: FuturesState[World] => + val response = HttpResponse.builder.setContent(state.futures.map(_.getNow)).build() + stack.`return`(response) + } + + // Test 5: Database updates + private def handleUpdateQuery(stack: AskStack[UpdateRequest]): StackYield = { + stack.state match + case _: StartState => + stack.suspend(selectWorlds(normalizeQueries(stack.ask.params))) + case state: FuturesState[World] => + val worlds = state.futures.map(_.getNow) + stack.attach(worlds) + val newState = FutureState[ModifyRows]() + val newWorlds = worlds.sortBy(_.id).map(_.copy(randomNumber = randomWorld())) + connection.ask(PrepareQuery.update(UPDATE_WORLD, newWorlds), newState.future) + stack.suspend(newState) + case state: FutureState[ModifyRows] => + if (state.future.isFailed) state.future.causeUnsafe.printStackTrace() + val response = HttpResponse.builder.setContent(stack.attach[Seq[World]]).build() + stack.`return`(response) + } + + private def selectWorlds(queries: Int): StackState = { + val state = FuturesState[World](queries) + for (future <- state.futures) + connection.ask(PrepareQuery.fetchOne[World](SELECT_WORLD, Tuple1(randomWorld())), future) + state + } + + private def randomWorld(): Int = 1 + random.nextInt(10000) + + private def normalizeQueries(params: Map[String, String]): Int = { + params.get("queries") match + case Some(value) => + try { + val queries = value.toInt + if (queries < 1) 1 else if (queries > 500) 500 else queries + } catch { + case e: Throwable => 1 + } + case None => 1 + } + +} + +object DBController { + + type REQ = SingleQueryRequest | MultipleQueryRequest | UpdateRequest + + class SingleQueryRequest extends HttpRequest[Nothing, World] + class MultipleQueryRequest extends HttpRequest[Nothing, HttpResponse[Seq[World]]] + class UpdateRequest extends HttpRequest[Nothing, HttpResponse[Seq[World]]] + + private val SELECT_WORLD = "SELECT id, randomnumber from WORLD where id=$1" + private val UPDATE_WORLD = "update world set randomnumber=$2 where id=$1" + +} diff --git a/frameworks/Scala/otavia/benchmark/src/app/controller/FortuneController.scala b/frameworks/Scala/otavia/benchmark/src/app/controller/FortuneController.scala new file mode 100644 index 00000000000..05ff8c468ba --- /dev/null +++ b/frameworks/Scala/otavia/benchmark/src/app/controller/FortuneController.scala @@ -0,0 +1,41 @@ +package app.controller + +import app.controller.FortuneController.* +import app.model.Fortune +import cc.otavia.core.actor.{MessageOf, StateActor} +import cc.otavia.core.address.Address +import cc.otavia.core.stack.helper.{FutureState, StartState} +import cc.otavia.core.stack.{AskStack, StackState, StackYield} +import cc.otavia.http.server.{HttpRequest, HttpResponse} +import cc.otavia.sql.Statement.PrepareQuery +import cc.otavia.sql.{Connection, RowSet} + +class FortuneController extends StateActor[FortuneRequest] { + + private var connection: Address[MessageOf[Connection]] = _ + + override protected def afterMount(): Unit = connection = autowire[Connection]() + + // Test 4: Fortunes + override protected def resumeAsk(stack: AskStack[FortuneRequest]): StackYield = { + stack.state match + case _: StartState => + val state = FutureState[RowSet[Fortune]]() + connection.ask(PrepareQuery.fetchAll[Fortune](SELECT_FORTUNE), state.future) + stack.suspend(state) + case state: FutureState[RowSet[Fortune]] => + val fortunes = (state.future.getNow.rows :+ Fortune(0, "Additional fortune added at request time.")) + .sortBy(_.message) + val response = HttpResponse.builder.setContent(fortunes).build() + stack.`return`(response) + } + +} + +object FortuneController { + + class FortuneRequest extends HttpRequest[Nothing, HttpResponse[Seq[Fortune]]] + + private val SELECT_FORTUNE = "SELECT id, message from FORTUNE" + +} diff --git a/frameworks/Scala/otavia/benchmark/src/app/model/Fortune.scala b/frameworks/Scala/otavia/benchmark/src/app/model/Fortune.scala new file mode 100644 index 00000000000..edb58d3cdc9 --- /dev/null +++ b/frameworks/Scala/otavia/benchmark/src/app/model/Fortune.scala @@ -0,0 +1,7 @@ +package app.model + +import cc.otavia.json.JsonSerde +import cc.otavia.sql.{Row, RowDecoder} + +/** The model for the "fortune" database table. */ +case class Fortune(id: Int, message: String) extends Row derives RowDecoder, JsonSerde diff --git a/frameworks/Scala/otavia/benchmark/src/app/model/Message.scala b/frameworks/Scala/otavia/benchmark/src/app/model/Message.scala new file mode 100644 index 00000000000..a0d389090ae --- /dev/null +++ b/frameworks/Scala/otavia/benchmark/src/app/model/Message.scala @@ -0,0 +1,5 @@ +package app.model + +import cc.otavia.json.JsonSerde + +case class Message(message: String) derives JsonSerde diff --git a/frameworks/Scala/otavia/benchmark/src/app/model/World.scala b/frameworks/Scala/otavia/benchmark/src/app/model/World.scala new file mode 100644 index 00000000000..a0e6f6056f8 --- /dev/null +++ b/frameworks/Scala/otavia/benchmark/src/app/model/World.scala @@ -0,0 +1,8 @@ +package app.model + +import cc.otavia.json.JsonSerde +import cc.otavia.serde.annotation.rename +import cc.otavia.sql.{Row, RowDecoder} + +/** The model for the "world" database table. */ +case class World(id: Int, @rename("randomnumber") randomNumber: Int) extends Row derives RowDecoder, JsonSerde diff --git a/frameworks/Scala/otavia/benchmark/src/app/startup.scala b/frameworks/Scala/otavia/benchmark/src/app/startup.scala new file mode 100644 index 00000000000..32eb0c2e539 --- /dev/null +++ b/frameworks/Scala/otavia/benchmark/src/app/startup.scala @@ -0,0 +1,70 @@ +package app + +import app.controller.DBController.* +import app.controller.FortuneController.* +import app.controller.{DBController, FortuneController} +import app.model.* +import app.util.FortunesRender +import cc.otavia.core.actor.ChannelsActor.{Bind, ChannelEstablished} +import cc.otavia.core.actor.MainActor +import cc.otavia.core.slf4a.LoggerFactory +import cc.otavia.core.stack.helper.{FutureState, StartState} +import cc.otavia.core.stack.{NoticeStack, StackYield} +import cc.otavia.core.system.ActorSystem +import cc.otavia.http.HttpMethod.* +import cc.otavia.http.MediaType +import cc.otavia.http.MediaType.* +import cc.otavia.http.server.* +import cc.otavia.http.server.Router.* +import cc.otavia.json.JsonSerde +import cc.otavia.serde.helper.BytesSerde +import cc.otavia.sql.Connection + +import java.io.File +import java.nio.charset.StandardCharsets.UTF_8 +import java.nio.file.Path + +private class ServerMain(val port: Int = 8080) extends MainActor(Array.empty) { + + override def main0(stack: NoticeStack[MainActor.Args]): StackYield = stack.state match + case _: StartState => + val worldResponseSerde = HttpResponseSerde.json(summon[JsonSerde[World]]) + val worldsResponseSerde = HttpResponseSerde.json(JsonSerde.derived[Seq[World]]) + val fortunesResponseSerde = HttpResponseSerde(new FortunesRender(), MediaType.TEXT_HTML_UTF8) + + val dbController = autowire[DBController]() + val fortuneController = autowire[FortuneController]() + + val routers = Seq( + // Test 6: plaintext + constant[Array[Byte]](GET, "/plaintext", "Hello, World!".getBytes(UTF_8), BytesSerde, TEXT_PLAIN_UTF8), + // Test 1: JSON serialization + constant[Message](GET, "/json", Message("Hello, World!"), summon[JsonSerde[Message]], APP_JSON), + // Test 2: Single database query. + get("/db", dbController, () => new SingleQueryRequest(), worldResponseSerde), + // Test 3: Multiple database queries + get("/queries", dbController, () => new MultipleQueryRequest(), worldsResponseSerde), + // Test 5: Database updates + get("/updates", dbController, () => new UpdateRequest(), worldsResponseSerde), + // Test 4: Fortunes + get("/fortunes", fortuneController, () => new FortuneRequest(), fortunesResponseSerde) + ) + val server = system.buildActor(() => new HttpServer(system.actorWorkerSize, routers)) + val state = FutureState[ChannelEstablished]() + server.ask(Bind(port), state.future) + stack.suspend(state) + case state: FutureState[ChannelEstablished] => + if (state.future.isFailed) state.future.causeUnsafe.printStackTrace() + logger.info(s"http server bind port $port success") + stack.`return`() + +} + +@main def startup(url: String, user: String, password: String, poolSize: Int): Unit = + val system = ActorSystem() + val logger = LoggerFactory.getLogger("startup", system) + logger.info("starting http server") + system.buildActor(() => new Connection(url, user, password), global = true, num = poolSize) + system.buildActor(() => new DBController(), global = true, num = system.actorWorkerSize) + system.buildActor(() => new FortuneController(), global = true, num = system.actorWorkerSize) + system.buildActor(() => new ServerMain()) diff --git a/frameworks/Scala/otavia/benchmark/src/app/util/FortunesRender.scala b/frameworks/Scala/otavia/benchmark/src/app/util/FortunesRender.scala new file mode 100644 index 00000000000..0c0694ee836 --- /dev/null +++ b/frameworks/Scala/otavia/benchmark/src/app/util/FortunesRender.scala @@ -0,0 +1,64 @@ +package app.util + +import app.model.Fortune +import cc.otavia.buffer.{Buffer, BufferUtils} +import cc.otavia.serde.Serde + +import java.nio.charset.StandardCharsets +import scala.annotation.switch + +class FortunesRender extends Serde[Seq[Fortune]] { + + private val text1 = + "Fortunes" + .getBytes(StandardCharsets.UTF_8) + + private val text2 = "".getBytes(StandardCharsets.UTF_8) + + private val text5 = "
idmessage
".getBytes(StandardCharsets.UTF_8) + + private val text3 = "".getBytes(StandardCharsets.UTF_8) + + private val text4 = "
".getBytes(StandardCharsets.UTF_8) + + private val lt = "<".getBytes() + private val gt = ">".getBytes() + private val quot = """.getBytes() + private val squot = "'".getBytes() + private val amp = "&".getBytes() + + override def serialize(fortunes: Seq[Fortune], out: Buffer): Unit = { + out.writeBytes(text1) + for (fortune <- fortunes) { + out.writeBytes(text2) + BufferUtils.writeIntAsString(out, fortune.id) + out.writeBytes(text3) + writeEscapeMessage(out, fortune.message) + out.writeBytes(text4) + } + out.writeBytes(text5) + } + + override def deserialize(in: Buffer): Seq[Fortune] = throw new UnsupportedOperationException() + + private def writeEscapeMessage(buffer: Buffer, message: String): Unit = { + var i = 0 + while (i < message.length) { + val ch = message.charAt(i) + writeChar(buffer, ch) + i += 1 + } + } + + private def writeChar(buffer: Buffer, ch: Char): Unit = (ch: @switch) match + case '<' => buffer.writeBytes(lt) + case '>' => buffer.writeBytes(gt) + case '"' => buffer.writeBytes(quot) + case '\'' => buffer.writeBytes(squot) + case '&' => buffer.writeBytes(amp) + case _ => + if (ch < 0x80) buffer.writeByte(ch.toByte) + else if (ch < 0x800) buffer.writeShortLE((ch >> 6 | (ch << 8 & 0x3f00) | 0x80c0).toShort) + else buffer.writeMediumLE(ch >> 12 | (ch << 2 & 0x3f00) | (ch << 16 & 0x3f0000) | 0x8080e0) + +} diff --git a/frameworks/Scala/otavia/benchmark_config.json b/frameworks/Scala/otavia/benchmark_config.json new file mode 100644 index 00000000000..ae712574778 --- /dev/null +++ b/frameworks/Scala/otavia/benchmark_config.json @@ -0,0 +1,53 @@ +{ + "framework": "otavia", + "tests": [ + { + "default": { + "json_url": "/json", + "plaintext_url": "/plaintext", + "db_url": "/db", + "query_url": "/queries?queries=", + "fortune_url": "/fortunes", + "update_url": "/updates?queries=", + "port": 8080, + "approach": "Realistic", + "classification": "Micro", + "database": "Postgres", + "framework": "otavia", + "language": "Scala", + "flavor": "None", + "orm": "Micro", + "platform": "Otavia", + "webserver": "None", + "os": "Linux", + "database_os": "Linux", + "display_name": "otavia", + "notes": "", + "versus": "Otavia" + }, + "reserve": { + "json_url": "/json", + "plaintext_url": "/plaintext", + "db_url": "/db", + "query_url": "/queries?queries=", + "fortune_url": "/fortunes", + "update_url": "/updates?queries=", + "port": 8080, + "approach": "Realistic", + "classification": "Micro", + "database": "Postgres", + "framework": "otavia", + "language": "Scala", + "flavor": "None", + "orm": "Micro", + "platform": "Otavia", + "webserver": "None", + "os": "Linux", + "database_os": "Linux", + "display_name": "otavia", + "notes": "", + "versus": "Otavia" + } + } + ] +} diff --git a/frameworks/Scala/otavia/build.sc b/frameworks/Scala/otavia/build.sc new file mode 100644 index 00000000000..2b7877b7891 --- /dev/null +++ b/frameworks/Scala/otavia/build.sc @@ -0,0 +1,15 @@ +import mill._ +import mill.scalalib._ + +def otaviaVersion = "0.4.0" + +object benchmark extends ScalaModule { + + override def scalaVersion = "3.3.1" + + override def ivyDeps = Agg( + ivy"cc.otavia::otavia-codec-http:$otaviaVersion", + ivy"cc.otavia::otavia-postgres-driver:$otaviaVersion" + ) + +} diff --git a/frameworks/Scala/otavia/config.toml b/frameworks/Scala/otavia/config.toml new file mode 100644 index 00000000000..96613dfd2fd --- /dev/null +++ b/frameworks/Scala/otavia/config.toml @@ -0,0 +1,36 @@ +[framework] +name = "otavia" + +[main] +urls.plaintext = "/plaintext" +urls.json = "/json" +urls.db = "/db" +urls.query = "/queries?queries=" +urls.update = "/updates?queries=" +urls.fortune = "/fortunes" +approach = "Realistic" +classification = "Micro" +database = "Postgres" +database_os = "Linux" +os = "Linux" +orm = "Micro" +platform = "Otavia" +webserver = "None" +versus = "Otavia" + +[reserve] +urls.plaintext = "/plaintext" +urls.json = "/json" +urls.db = "/db" +urls.query = "/queries?queries=" +urls.update = "/updates?queries=" +urls.fortune = "/fortunes" +approach = "Realistic" +classification = "Micro" +database = "Postgres" +database_os = "Linux" +os = "Linux" +orm = "Micro" +platform = "Otavia" +webserver = "None" +versus = "Otavia" diff --git a/frameworks/Scala/otavia/millw b/frameworks/Scala/otavia/millw new file mode 100644 index 00000000000..73bb4d0e4a0 --- /dev/null +++ b/frameworks/Scala/otavia/millw @@ -0,0 +1,194 @@ +#!/usr/bin/env sh + +# This is a wrapper script, that automatically download mill from GitHub release pages +# You can give the required mill version with --mill-version parameter +# If no version is given, it falls back to the value of DEFAULT_MILL_VERSION +# +# Project page: https://github.com/lefou/millw +# Script Version: 0.4.6 +# +# If you want to improve this script, please also contribute your changes back! +# +# Licensed under the Apache License, Version 2.0 + +set -e + +if [ -z "${DEFAULT_MILL_VERSION}" ] ; then + DEFAULT_MILL_VERSION="0.10.10" +fi + + +if [ -z "${GITHUB_RELEASE_CDN}" ] ; then + GITHUB_RELEASE_CDN="" +fi + + +MILL_REPO_URL="https://github.com/com-lihaoyi/mill" + +if [ -z "${CURL_CMD}" ] ; then + CURL_CMD=curl +fi + +# Explicit commandline argument takes precedence over all other methods +if [ "$1" = "--mill-version" ] ; then + shift + if [ "x$1" != "x" ] ; then + MILL_VERSION="$1" + shift + else + echo "You specified --mill-version without a version." 1>&2 + echo "Please provide a version that matches one provided on" 1>&2 + echo "${MILL_REPO_URL}/releases" 1>&2 + false + fi +fi + +# Please note, that if a MILL_VERSION is already set in the environment, +# We reuse it's value and skip searching for a value. + +# If not already set, read .mill-version file +if [ -z "${MILL_VERSION}" ] ; then + if [ -f ".mill-version" ] ; then + MILL_VERSION="$(head -n 1 .mill-version 2> /dev/null)" + elif [ -f ".config/mill-version" ] ; then + MILL_VERSION="$(head -n 1 .config/mill-version 2> /dev/null)" + fi +fi + +if [ -n "${XDG_CACHE_HOME}" ] ; then + MILL_DOWNLOAD_PATH="${XDG_CACHE_HOME}/mill/download" +else + MILL_DOWNLOAD_PATH="${HOME}/.cache/mill/download" +fi + +# If not already set, try to fetch newest from Github +if [ -z "${MILL_VERSION}" ] ; then + # TODO: try to load latest version from release page + echo "No mill version specified." 1>&2 + echo "You should provide a version via '.mill-version' file or --mill-version option." 1>&2 + + mkdir -p "${MILL_DOWNLOAD_PATH}" + LANG=C touch -d '1 hour ago' "${MILL_DOWNLOAD_PATH}/.expire_latest" 2>/dev/null || ( + # we might be on OSX or BSD which don't have -d option for touch + # but probably a -A [-][[hh]mm]SS + touch "${MILL_DOWNLOAD_PATH}/.expire_latest"; touch -A -010000 "${MILL_DOWNLOAD_PATH}/.expire_latest" + ) || ( + # in case we still failed, we retry the first touch command with the intention + # to show the (previously suppressed) error message + LANG=C touch -d '1 hour ago' "${MILL_DOWNLOAD_PATH}/.expire_latest" + ) + + # POSIX shell variant of bash's -nt operator, see https://unix.stackexchange.com/a/449744/6993 + # if [ "${MILL_DOWNLOAD_PATH}/.latest" -nt "${MILL_DOWNLOAD_PATH}/.expire_latest" ] ; then + if [ -n "$(find -L "${MILL_DOWNLOAD_PATH}/.latest" -prune -newer "${MILL_DOWNLOAD_PATH}/.expire_latest")" ]; then + # we know a current latest version + MILL_VERSION=$(head -n 1 "${MILL_DOWNLOAD_PATH}"/.latest 2> /dev/null) + fi + + if [ -z "${MILL_VERSION}" ] ; then + # we don't know a current latest version + echo "Retrieving latest mill version ..." 1>&2 + LANG=C ${CURL_CMD} -s -i -f -I ${MILL_REPO_URL}/releases/latest 2> /dev/null | grep --ignore-case Location: | sed s'/^.*tag\///' | tr -d '\r\n' > "${MILL_DOWNLOAD_PATH}/.latest" + MILL_VERSION=$(head -n 1 "${MILL_DOWNLOAD_PATH}"/.latest 2> /dev/null) + fi + + if [ -z "${MILL_VERSION}" ] ; then + # Last resort + MILL_VERSION="${DEFAULT_MILL_VERSION}" + echo "Falling back to hardcoded mill version ${MILL_VERSION}" 1>&2 + else + echo "Using mill version ${MILL_VERSION}" 1>&2 + fi +fi + +MILL="${MILL_DOWNLOAD_PATH}/${MILL_VERSION}" + +try_to_use_system_mill() { + MILL_IN_PATH="$(command -v mill || true)" + + if [ -z "${MILL_IN_PATH}" ]; then + return + fi + + UNIVERSAL_SCRIPT_MAGIC="@ 2>/dev/null # 2>nul & echo off & goto BOF" + + if ! head -c 128 "${MILL_IN_PATH}" | grep -qF "${UNIVERSAL_SCRIPT_MAGIC}"; then + if [ -n "${MILLW_VERBOSE}" ]; then + echo "Could not determine mill version of ${MILL_IN_PATH}, as it does not start with the universal script magic2" 1>&2 + fi + return + fi + + # Roughly the size of the universal script. + MILL_VERSION_SEARCH_RANGE="2403" + MILL_IN_PATH_VERSION=$(head -c "${MILL_VERSION_SEARCH_RANGE}" "${MILL_IN_PATH}" |\ + sed -n 's/^.*-DMILL_VERSION=\([^\s]*\) .*$/\1/p' |\ + head -n 1) + + if [ -z "${MILL_IN_PATH_VERSION}" ]; then + echo "Could not determine mill version, even though ${MILL_IN_PATH} has the universal script magic" 1>&2 + return + fi + + if [ "${MILL_IN_PATH_VERSION}" = "${MILL_VERSION}" ]; then + MILL="${MILL_IN_PATH}" + fi +} +try_to_use_system_mill + +# If not already downloaded, download it +if [ ! -s "${MILL}" ] ; then + + # support old non-XDG download dir + MILL_OLD_DOWNLOAD_PATH="${HOME}/.mill/download" + OLD_MILL="${MILL_OLD_DOWNLOAD_PATH}/${MILL_VERSION}" + if [ -x "${OLD_MILL}" ] ; then + MILL="${OLD_MILL}" + else + VERSION_PREFIX="$(echo $MILL_VERSION | cut -b -4)" + case $VERSION_PREFIX in + 0.0. | 0.1. | 0.2. | 0.3. | 0.4. ) + DOWNLOAD_SUFFIX="" + ;; + *) + DOWNLOAD_SUFFIX="-assembly" + ;; + esac + unset VERSION_PREFIX + + DOWNLOAD_FILE=$(mktemp mill.XXXXXX) + MILL_VERSION_TAG=$(echo $MILL_VERSION | sed -E 's/([^-]+)(-M[0-9]+)?(-.*)?/\1\2/') + DOWNLOAD_URL="${GITHUB_RELEASE_CDN}${MILL_REPO_URL}/releases/download/${MILL_VERSION_TAG}/${MILL_VERSION}${DOWNLOAD_SUFFIX}" + # TODO: handle command not found + echo "Downloading mill ${MILL_VERSION} from ${DOWNLOAD_URL} ..." 1>&2 + ${CURL_CMD} -f -L -o "${DOWNLOAD_FILE}" ${DOWNLOAD_URL} + chmod +x "${DOWNLOAD_FILE}" + mkdir -p "${MILL_DOWNLOAD_PATH}" + mv "${DOWNLOAD_FILE}" "${MILL}" + + unset DOWNLOAD_FILE + unset DOWNLOAD_SUFFIX + fi +fi + +if [ -z "$MILL_MAIN_CLI" ] ; then + MILL_MAIN_CLI="${0}" +fi + +MILL_FIRST_ARG="" +if [ "$1" = "--bsp" ] || [ "$1" = "-i" ] || [ "$1" = "--interactive" ] || [ "$1" = "--no-server" ] || [ "$1" = "--repl" ] || [ "$1" = "--help" ] ; then + # Need to preserve the first position of those listed options + MILL_FIRST_ARG=$1 + shift +fi + +unset MILL_DOWNLOAD_PATH +unset MILL_OLD_DOWNLOAD_PATH +unset OLD_MILL +unset MILL_VERSION +unset MILL_VERSION_TAG +unset MILL_REPO_URL + +# We don't quote MILL_FIRST_ARG on purpose, so we can expand the empty value without quotes +# shellcheck disable=SC2086 +exec "${MILL}" $MILL_FIRST_ARG -D "mill.main.cli=${MILL_MAIN_CLI}" "$@" diff --git a/frameworks/Scala/otavia/millw.bat b/frameworks/Scala/otavia/millw.bat new file mode 100644 index 00000000000..6359e35e500 --- /dev/null +++ b/frameworks/Scala/otavia/millw.bat @@ -0,0 +1,173 @@ +@echo off + +rem This is a wrapper script, that automatically download mill from GitHub release pages +rem You can give the required mill version with --mill-version parameter +rem If no version is given, it falls back to the value of DEFAULT_MILL_VERSION +rem +rem Project page: https://github.com/lefou/millw +rem Script Version: 0.4.6 +rem +rem If you want to improve this script, please also contribute your changes back! +rem +rem Licensed under the Apache License, Version 2.0 + +rem setlocal seems to be unavailable on Windows 95/98/ME +rem but I don't think we need to support them in 2019 +setlocal enabledelayedexpansion + +if [!DEFAULT_MILL_VERSION!]==[] ( + set "DEFAULT_MILL_VERSION=0.10.10" +) + +if [!GITHUB_RELEASE_CDN!]==[] ( + set "GITHUB_RELEASE_CDN=" +) + +set "MILL_REPO_URL=https://github.com/com-lihaoyi/mill" + +rem %~1% removes surrounding quotes +if [%~1%]==[--mill-version] ( + if not [%~2%]==[] ( + set MILL_VERSION=%~2% + rem shift command doesn't work within parentheses + set "STRIP_VERSION_PARAMS=true" + ) else ( + echo You specified --mill-version without a version. 1>&2 + echo Please provide a version that matches one provided on 1>&2 + echo %MILL_REPO_URL%/releases 1>&2 + exit /b 1 + ) +) + +if not defined STRIP_VERSION_PARAMS GOTO AfterStripVersionParams +rem strip the: --mill-version {version} +shift +shift +:AfterStripVersionParams + +if [!MILL_VERSION!]==[] ( + if exist .mill-version ( + set /p MILL_VERSION=<.mill-version + ) else ( + if exist .config\mill-version ( + set /p MILL_VERSION=<.config\mill-version + ) + ) +) + +if [!MILL_VERSION!]==[] ( + set MILL_VERSION=%DEFAULT_MILL_VERSION% +) + +set MILL_DOWNLOAD_PATH=%USERPROFILE%\.mill\download + +rem without bat file extension, cmd doesn't seem to be able to run it +set MILL=%MILL_DOWNLOAD_PATH%\!MILL_VERSION!.bat + +if not exist "%MILL%" ( + set VERSION_PREFIX=%MILL_VERSION:~0,4% + set DOWNLOAD_SUFFIX=-assembly + if [!VERSION_PREFIX!]==[0.0.] set DOWNLOAD_SUFFIX= + if [!VERSION_PREFIX!]==[0.1.] set DOWNLOAD_SUFFIX= + if [!VERSION_PREFIX!]==[0.2.] set DOWNLOAD_SUFFIX= + if [!VERSION_PREFIX!]==[0.3.] set DOWNLOAD_SUFFIX= + if [!VERSION_PREFIX!]==[0.4.] set DOWNLOAD_SUFFIX= + set VERSION_PREFIX= + + for /F "delims=- tokens=1" %%A in ("!MILL_VERSION!") do set MILL_VERSION_BASE=%%A + for /F "delims=- tokens=2" %%A in ("!MILL_VERSION!") do set MILL_VERSION_MILESTONE=%%A + set VERSION_MILESTONE_START=!MILL_VERSION_MILESTONE:~0,1! + if [!VERSION_MILESTONE_START!]==[M] ( + set MILL_VERSION_TAG="!MILL_VERSION_BASE!-!MILL_VERSION_MILESTONE!" + ) else ( + set MILL_VERSION_TAG=!MILL_VERSION_BASE! + ) + + rem there seems to be no way to generate a unique temporary file path (on native Windows) + set DOWNLOAD_FILE=%MILL%.tmp + + set DOWNLOAD_URL=!GITHUB_RELEASE_CDN!%MILL_REPO_URL%/releases/download/!MILL_VERSION_TAG!/!MILL_VERSION!!DOWNLOAD_SUFFIX! + + echo Downloading mill %MILL_VERSION% from !DOWNLOAD_URL! ... 1>&2 + + if not exist "%MILL_DOWNLOAD_PATH%" mkdir "%MILL_DOWNLOAD_PATH%" + rem curl is bundled with recent Windows 10 + rem but I don't think we can expect all the users to have it in 2019 + where /Q curl + if %ERRORLEVEL% EQU 0 ( + curl -f -L "!DOWNLOAD_URL!" -o "!DOWNLOAD_FILE!" + ) else ( + rem bitsadmin seems to be available on Windows 7 + rem without /dynamic, github returns 403 + rem bitsadmin is sometimes needlessly slow but it looks better with /priority foreground + bitsadmin /transfer millDownloadJob /dynamic /priority foreground "!DOWNLOAD_URL!" "!DOWNLOAD_FILE!" + ) + if not exist "!DOWNLOAD_FILE!" ( + echo Could not download mill %MILL_VERSION% 1>&2 + exit /b 1 + ) + + move /y "!DOWNLOAD_FILE!" "%MILL%" + + set DOWNLOAD_FILE= + set DOWNLOAD_SUFFIX= +) + +set MILL_DOWNLOAD_PATH= +set MILL_VERSION= +set MILL_REPO_URL= + +if [!MILL_MAIN_CLI!]==[] ( + set "MILL_MAIN_CLI=%0" +) + +rem Need to preserve the first position of those listed options +set MILL_FIRST_ARG= +if [%~1%]==[--bsp] ( + set MILL_FIRST_ARG=%1% +) else ( + if [%~1%]==[-i] ( + set MILL_FIRST_ARG=%1% + ) else ( + if [%~1%]==[--interactive] ( + set MILL_FIRST_ARG=%1% + ) else ( + if [%~1%]==[--no-server] ( + set MILL_FIRST_ARG=%1% + ) else ( + if [%~1%]==[--repl] ( + set MILL_FIRST_ARG=%1% + ) else ( + if [%~1%]==[--help] ( + set MILL_FIRST_ARG=%1% + ) + ) + ) + ) + ) +) + +set "MILL_PARAMS=%*%" + +if not [!MILL_FIRST_ARG!]==[] ( + if defined STRIP_VERSION_PARAMS ( + for /f "tokens=1-3*" %%a in ("%*") do ( + set "MILL_PARAMS=%%d" + ) + ) else ( + for /f "tokens=1*" %%a in ("%*") do ( + set "MILL_PARAMS=%%b" + ) + ) +) else ( + if defined STRIP_VERSION_PARAMS ( + for /f "tokens=1-2*" %%a in ("%*") do ( + rem strip %%a - It's the "--mill-version" option. + rem strip %%b - it's the version number that comes after the option. + rem keep %%c - It's the remaining options. + set "MILL_PARAMS=%%c" + ) + ) +) + +"%MILL%" %MILL_FIRST_ARG% -D "mill.main.cli=%MILL_MAIN_CLI%" %MILL_PARAMS% diff --git a/frameworks/Scala/otavia/otavia-reserve.dockerfile b/frameworks/Scala/otavia/otavia-reserve.dockerfile new file mode 100644 index 00000000000..5768000706e --- /dev/null +++ b/frameworks/Scala/otavia/otavia-reserve.dockerfile @@ -0,0 +1,15 @@ +FROM nightscape/scala-mill:eclipse-temurin-17.0.8.1_1-jdk-focal_0.11.6_3.3.0 +WORKDIR /otavia +COPY benchmark benchmark +COPY build.sc build.sc +ENV COURSIER_REPOSITORIES=ivy2Local|central +RUN mill benchmark.assembly + +EXPOSE 8080 + +CMD java -server \ + -Dcc.otavia.actor.worker.size=18 -Dcc.otavia.nio.worker.size=36 \ + -jar \ + out/benchmark/assembly.dest/out.jar \ + jdbc:postgresql://tfb-database:5432/hello_world \ + benchmarkdbuser benchmarkdbpass 54 diff --git a/frameworks/Scala/otavia/otavia.dockerfile b/frameworks/Scala/otavia/otavia.dockerfile new file mode 100644 index 00000000000..c1c944d60aa --- /dev/null +++ b/frameworks/Scala/otavia/otavia.dockerfile @@ -0,0 +1,15 @@ +FROM nightscape/scala-mill:eclipse-temurin-17.0.8.1_1-jdk-focal_0.11.6_3.3.0 +WORKDIR /otavia +COPY benchmark benchmark +COPY build.sc build.sc +ENV COURSIER_REPOSITORIES=ivy2Local|central +RUN mill benchmark.assembly + +EXPOSE 8080 + +CMD java -server \ + -Dcc.otavia.actor.worker.size=24 -Dcc.otavia.nio.worker.size=48 \ + -jar \ + out/benchmark/assembly.dest/out.jar \ + jdbc:postgresql://tfb-database:5432/hello_world \ + benchmarkdbuser benchmarkdbpass 72 From c4443eb4b04a63f6010d51d411dfe286a301dc81 Mon Sep 17 00:00:00 2001 From: Julien Viet Date: Thu, 8 Aug 2024 22:04:37 +0200 Subject: [PATCH 057/204] Update to jsonsergen 0.0.5 with the JsonDsl backend (#9190) --- frameworks/Java/vertx/pom.xml | 8 ++++---- .../Java/vertx/src/main/java/vertx/model/CachedWorld.java | 3 ++- .../Java/vertx/src/main/java/vertx/model/Message.java | 3 ++- .../Java/vertx/src/main/java/vertx/model/World.java | 3 ++- 4 files changed, 10 insertions(+), 7 deletions(-) diff --git a/frameworks/Java/vertx/pom.xml b/frameworks/Java/vertx/pom.xml index 12eff9d69a5..06199d308db 100644 --- a/frameworks/Java/vertx/pom.xml +++ b/frameworks/Java/vertx/pom.xml @@ -28,14 +28,14 @@ ${stack.version} - com.fasterxml.jackson.core - jackson-core - ${jackson.version} + com.dslplatform + dsl-json + 2.0.2 com.julienviet jsonsergen - 0.0.4 + 0.0.5 io.netty diff --git a/frameworks/Java/vertx/src/main/java/vertx/model/CachedWorld.java b/frameworks/Java/vertx/src/main/java/vertx/model/CachedWorld.java index 423d5273f62..3a55bfc2e89 100644 --- a/frameworks/Java/vertx/src/main/java/vertx/model/CachedWorld.java +++ b/frameworks/Java/vertx/src/main/java/vertx/model/CachedWorld.java @@ -1,5 +1,6 @@ package vertx.model; +import com.julienviet.jsonsergen.Backend; import com.julienviet.jsonsergen.JsonSerGen; import io.vertx.codegen.annotations.DataObject; import io.vertx.core.buffer.Buffer; @@ -10,7 +11,7 @@ * The model for the "world" database table. */ @DataObject -@JsonSerGen +@JsonSerGen(backends = Backend.DSL_JSON) public final class CachedWorld implements Comparable { private final int id; diff --git a/frameworks/Java/vertx/src/main/java/vertx/model/Message.java b/frameworks/Java/vertx/src/main/java/vertx/model/Message.java index ce240bd5ae9..ab9cd2a3d48 100644 --- a/frameworks/Java/vertx/src/main/java/vertx/model/Message.java +++ b/frameworks/Java/vertx/src/main/java/vertx/model/Message.java @@ -1,11 +1,12 @@ package vertx.model; +import com.julienviet.jsonsergen.Backend; import com.julienviet.jsonsergen.JsonSerGen; import io.vertx.codegen.annotations.DataObject; import io.vertx.core.buffer.Buffer; @DataObject -@JsonSerGen +@JsonSerGen(backends = Backend.DSL_JSON) public class Message { private String message; diff --git a/frameworks/Java/vertx/src/main/java/vertx/model/World.java b/frameworks/Java/vertx/src/main/java/vertx/model/World.java index 43f7bfc2a61..610f4371cab 100644 --- a/frameworks/Java/vertx/src/main/java/vertx/model/World.java +++ b/frameworks/Java/vertx/src/main/java/vertx/model/World.java @@ -1,5 +1,6 @@ package vertx.model; +import com.julienviet.jsonsergen.Backend; import com.julienviet.jsonsergen.JsonSerGen; import io.vertx.codegen.annotations.DataObject; import io.vertx.core.buffer.Buffer; @@ -8,7 +9,7 @@ * The model for the "world" database table. */ @DataObject -@JsonSerGen +@JsonSerGen(backends = Backend.DSL_JSON) public final class World implements Comparable { private final int id; From 8d801c857067756c18f7ecec8da58e98ff5e97bd Mon Sep 17 00:00:00 2001 From: Juanjo Aguililla Date: Thu, 8 Aug 2024 22:04:53 +0200 Subject: [PATCH 058/204] [Kotlin/Hexagon] Update Hexagon and dependencies' versions (#9191) * Clean up * Avoid classpath URLs * Fix template loading error * Fix template loading error * Chores * Fix template loading error * Delete MongoDB DB support Storage support in Hexagon will be moved outside the Toolkit, and so, it will be left outside the benchmark. * Fix runtime problem * Update Hexagon version * Make Jackson Blackbird module optional * Add variation with Blackbird module enabled * Upgrade Hexagon version * Enable blackbird Jackson module by default * Update dependencies * Use Hexagon version 2.0.0-B1 (and a little cleanup) * Use Hexagon version 2.0.0-B1 (and a little cleanup) * Use Tomcat instead Resin to test JEE integration * Remove unused environment variable * Clean Tomcat dockerfile * Minor improvements * Minor improvements * Update to release version * Update to the latest Hexagon release * Add Netty adapter test * Remove Gradle Wrapper * Update version * Update version * Minimize template * Skip Hexagon checks in the container * Add Netty Epoll benchmark * Database and template improvements * Update Hexagon version * Update Hexagon version * Update DB settings * Use a single store and template engine to simplify benchmark * Bump mysql-connector-java in /frameworks/Java/wicket Bumps [mysql-connector-java](https://github.com/mysql/mysql-connector-j) from 8.0.27 to 8.0.28. - [Release notes](https://github.com/mysql/mysql-connector-j/releases) - [Changelog](https://github.com/mysql/mysql-connector-j/blob/release/8.0/CHANGES) - [Commits](https://github.com/mysql/mysql-connector-j/compare/8.0.27...8.0.28) --- updated-dependencies: - dependency-name: mysql:mysql-connector-java dependency-type: direct:production ... Signed-off-by: dependabot[bot] * Bump mongodb-driver-sync from 4.2.0 to 4.2.1 in /frameworks/Java/javalin Bumps [mongodb-driver-sync](https://github.com/mongodb/mongo-java-driver) from 4.2.0 to 4.2.1. - [Release notes](https://github.com/mongodb/mongo-java-driver/releases) - [Commits](https://github.com/mongodb/mongo-java-driver/compare/r4.2.0...r4.2.1) --- updated-dependencies: - dependency-name: org.mongodb:mongodb-driver-sync dependency-type: direct:production ... Signed-off-by: dependabot[bot] * Bump ujson from 5.2.0 to 5.4.0 in /frameworks/Python/starlette Bumps [ujson](https://github.com/ultrajson/ultrajson) from 5.2.0 to 5.4.0. - [Release notes](https://github.com/ultrajson/ultrajson/releases) - [Commits](https://github.com/ultrajson/ultrajson/compare/5.2.0...5.4.0) --- updated-dependencies: - dependency-name: ujson dependency-type: direct:production ... Signed-off-by: dependabot[bot] * Bump ujson from 5.2.0 to 5.4.0 in /frameworks/Python/django Bumps [ujson](https://github.com/ultrajson/ultrajson) from 5.2.0 to 5.4.0. - [Release notes](https://github.com/ultrajson/ultrajson/releases) - [Commits](https://github.com/ultrajson/ultrajson/compare/5.2.0...5.4.0) --- updated-dependencies: - dependency-name: ujson dependency-type: direct:production ... Signed-off-by: dependabot[bot] * Bump ujson from 5.2.0 to 5.4.0 in /frameworks/Python/routerling Bumps [ujson](https://github.com/ultrajson/ultrajson) from 5.2.0 to 5.4.0. - [Release notes](https://github.com/ultrajson/ultrajson/releases) - [Commits](https://github.com/ultrajson/ultrajson/compare/5.2.0...5.4.0) --- updated-dependencies: - dependency-name: ujson dependency-type: direct:production ... Signed-off-by: dependabot[bot] * Bump ujson from 5.2.0 to 5.4.0 in /frameworks/Python/japronto Bumps [ujson](https://github.com/ultrajson/ultrajson) from 5.2.0 to 5.4.0. - [Release notes](https://github.com/ultrajson/ultrajson/releases) - [Commits](https://github.com/ultrajson/ultrajson/compare/5.2.0...5.4.0) --- updated-dependencies: - dependency-name: ujson dependency-type: direct:production ... Signed-off-by: dependabot[bot] * Bump ujson from 5.2.0 to 5.4.0 in /frameworks/Python/fastapi Bumps [ujson](https://github.com/ultrajson/ultrajson) from 5.2.0 to 5.4.0. - [Release notes](https://github.com/ultrajson/ultrajson/releases) - [Commits](https://github.com/ultrajson/ultrajson/compare/5.2.0...5.4.0) --- updated-dependencies: - dependency-name: ujson dependency-type: direct:production ... Signed-off-by: dependabot[bot] * Bump ujson from 5.2.0 to 5.4.0 in /frameworks/Python/uvicorn Bumps [ujson](https://github.com/ultrajson/ultrajson) from 5.2.0 to 5.4.0. - [Release notes](https://github.com/ultrajson/ultrajson/releases) - [Commits](https://github.com/ultrajson/ultrajson/compare/5.2.0...5.4.0) --- updated-dependencies: - dependency-name: ujson dependency-type: direct:production ... Signed-off-by: dependabot[bot] * Bump ujson from 5.2.0 to 5.4.0 in /frameworks/Python/flask Bumps [ujson](https://github.com/ultrajson/ultrajson) from 5.2.0 to 5.4.0. - [Release notes](https://github.com/ultrajson/ultrajson/releases) - [Commits](https://github.com/ultrajson/ultrajson/compare/5.2.0...5.4.0) --- updated-dependencies: - dependency-name: ujson dependency-type: direct:production ... Signed-off-by: dependabot[bot] * Bump ujson from 5.1 to 5.4.0 in /frameworks/Python/aiohttp Bumps [ujson](https://github.com/ultrajson/ultrajson) from 5.1 to 5.4.0. - [Release notes](https://github.com/ultrajson/ultrajson/releases) - [Commits](https://github.com/ultrajson/ultrajson/compare/5.1.0...5.4.0) --- updated-dependencies: - dependency-name: ujson dependency-type: direct:production ... Signed-off-by: dependabot[bot] * Bump rails-html-sanitizer from 1.4.2 to 1.4.3 in /frameworks/Ruby/rails Bumps [rails-html-sanitizer](https://github.com/rails/rails-html-sanitizer) from 1.4.2 to 1.4.3. - [Release notes](https://github.com/rails/rails-html-sanitizer/releases) - [Changelog](https://github.com/rails/rails-html-sanitizer/blob/master/CHANGELOG.md) - [Commits](https://github.com/rails/rails-html-sanitizer/compare/v1.4.2...v1.4.3) --- updated-dependencies: - dependency-name: rails-html-sanitizer dependency-type: indirect ... Signed-off-by: dependabot[bot] * Bump jetty-server in /frameworks/Java/jetty Bumps [jetty-server](https://github.com/eclipse/jetty.project) from 9.4.41.v20210516 to 10.0.10. - [Release notes](https://github.com/eclipse/jetty.project/releases) - [Commits](https://github.com/eclipse/jetty.project/compare/jetty-9.4.41.v20210516...jetty-10.0.10) --- updated-dependencies: - dependency-name: org.eclipse.jetty:jetty-server dependency-type: direct:production ... Signed-off-by: dependabot[bot] * Bump undertow-core in /frameworks/Java/undertow Bumps [undertow-core](https://github.com/undertow-io/undertow) from 2.2.11.Final to 2.2.15.Final. - [Release notes](https://github.com/undertow-io/undertow/releases) - [Commits](https://github.com/undertow-io/undertow/compare/2.2.11.Final...2.2.15.Final) --- updated-dependencies: - dependency-name: io.undertow:undertow-core dependency-type: direct:production ... Signed-off-by: dependabot[bot] * Update versions * Update README.md * Bump sanic from 22.3.1 to 22.6.1 in /frameworks/Python/sanic Bumps [sanic](https://github.com/sanic-org/sanic) from 22.3.1 to 22.6.1. - [Release notes](https://github.com/sanic-org/sanic/releases) - [Changelog](https://github.com/sanic-org/sanic/blob/main/CHANGELOG.rst) - [Commits](https://github.com/sanic-org/sanic/compare/v22.3.1...v22.6.1) --- updated-dependencies: - dependency-name: sanic dependency-type: direct:production ... Signed-off-by: dependabot[bot] * Bump postgresql from 42.3.3 to 42.4.1 in /frameworks/Java/light-java Bumps [postgresql](https://github.com/pgjdbc/pgjdbc) from 42.3.3 to 42.4.1. - [Release notes](https://github.com/pgjdbc/pgjdbc/releases) - [Changelog](https://github.com/pgjdbc/pgjdbc/blob/master/CHANGELOG.md) - [Commits](https://github.com/pgjdbc/pgjdbc/compare/REL42.3.3...REL42.4.1) --- updated-dependencies: - dependency-name: org.postgresql:postgresql dependency-type: direct:production ... Signed-off-by: dependabot[bot] * Bump postgresql from 42.3.3 to 42.4.1 in /frameworks/Java/rapidoid Bumps [postgresql](https://github.com/pgjdbc/pgjdbc) from 42.3.3 to 42.4.1. - [Release notes](https://github.com/pgjdbc/pgjdbc/releases) - [Changelog](https://github.com/pgjdbc/pgjdbc/blob/master/CHANGELOG.md) - [Commits](https://github.com/pgjdbc/pgjdbc/compare/REL42.3.3...REL42.4.1) --- updated-dependencies: - dependency-name: org.postgresql:postgresql dependency-type: direct:production ... Signed-off-by: dependabot[bot] * Bump postgresql from 42.3.3 to 42.4.1 in /frameworks/Java/jooby Bumps [postgresql](https://github.com/pgjdbc/pgjdbc) from 42.3.3 to 42.4.1. - [Release notes](https://github.com/pgjdbc/pgjdbc/releases) - [Changelog](https://github.com/pgjdbc/pgjdbc/blob/master/CHANGELOG.md) - [Commits](https://github.com/pgjdbc/pgjdbc/compare/REL42.3.3...REL42.4.1) --- updated-dependencies: - dependency-name: org.postgresql:postgresql dependency-type: direct:production ... Signed-off-by: dependabot[bot] * Bump postgresql from 42.3.3 to 42.4.1 in /frameworks/Java/servlet Bumps [postgresql](https://github.com/pgjdbc/pgjdbc) from 42.3.3 to 42.4.1. - [Release notes](https://github.com/pgjdbc/pgjdbc/releases) - [Changelog](https://github.com/pgjdbc/pgjdbc/blob/master/CHANGELOG.md) - [Commits](https://github.com/pgjdbc/pgjdbc/compare/REL42.3.3...REL42.4.1) --- updated-dependencies: - dependency-name: org.postgresql:postgresql dependency-type: direct:production ... Signed-off-by: dependabot[bot] * Bump postgresql from 42.3.3 to 42.4.1 in /frameworks/Java/spring-webflux Bumps [postgresql](https://github.com/pgjdbc/pgjdbc) from 42.3.3 to 42.4.1. - [Release notes](https://github.com/pgjdbc/pgjdbc/releases) - [Changelog](https://github.com/pgjdbc/pgjdbc/blob/master/CHANGELOG.md) - [Commits](https://github.com/pgjdbc/pgjdbc/compare/REL42.3.3...REL42.4.1) --- updated-dependencies: - dependency-name: org.postgresql:postgresql dependency-type: direct:production ... Signed-off-by: dependabot[bot] * Bump postgresql from 42.3.3 to 42.4.1 in /frameworks/Java/smart-socket Bumps [postgresql](https://github.com/pgjdbc/pgjdbc) from 42.3.3 to 42.4.1. - [Release notes](https://github.com/pgjdbc/pgjdbc/releases) - [Changelog](https://github.com/pgjdbc/pgjdbc/blob/master/CHANGELOG.md) - [Commits](https://github.com/pgjdbc/pgjdbc/compare/REL42.3.3...REL42.4.1) --- updated-dependencies: - dependency-name: org.postgresql:postgresql dependency-type: direct:production ... Signed-off-by: dependabot[bot] * Bump postgresql from 42.3.3 to 42.4.1 in /frameworks/Java/act Bumps [postgresql](https://github.com/pgjdbc/pgjdbc) from 42.3.3 to 42.4.1. - [Release notes](https://github.com/pgjdbc/pgjdbc/releases) - [Changelog](https://github.com/pgjdbc/pgjdbc/blob/master/CHANGELOG.md) - [Commits](https://github.com/pgjdbc/pgjdbc/compare/REL42.3.3...REL42.4.1) --- updated-dependencies: - dependency-name: org.postgresql:postgresql dependency-type: direct:production ... Signed-off-by: dependabot[bot] * Bump postgresql from 42.3.3 to 42.4.1 in /frameworks/Kotlin/kooby Bumps [postgresql](https://github.com/pgjdbc/pgjdbc) from 42.3.3 to 42.4.1. - [Release notes](https://github.com/pgjdbc/pgjdbc/releases) - [Changelog](https://github.com/pgjdbc/pgjdbc/blob/master/CHANGELOG.md) - [Commits](https://github.com/pgjdbc/pgjdbc/compare/REL42.3.3...REL42.4.1) --- updated-dependencies: - dependency-name: org.postgresql:postgresql dependency-type: direct:production ... Signed-off-by: dependabot[bot] * Bump postgresql from 42.3.3 to 42.4.1 in /frameworks/Java/dropwizard Bumps [postgresql](https://github.com/pgjdbc/pgjdbc) from 42.3.3 to 42.4.1. - [Release notes](https://github.com/pgjdbc/pgjdbc/releases) - [Changelog](https://github.com/pgjdbc/pgjdbc/blob/master/CHANGELOG.md) - [Commits](https://github.com/pgjdbc/pgjdbc/compare/REL42.3.3...REL42.4.1) --- updated-dependencies: - dependency-name: org.postgresql:postgresql dependency-type: direct:production ... Signed-off-by: dependabot[bot] * Bump postgresql from 42.3.3 to 42.4.1 in /frameworks/Java/hserver Bumps [postgresql](https://github.com/pgjdbc/pgjdbc) from 42.3.3 to 42.4.1. - [Release notes](https://github.com/pgjdbc/pgjdbc/releases) - [Changelog](https://github.com/pgjdbc/pgjdbc/blob/master/CHANGELOG.md) - [Commits](https://github.com/pgjdbc/pgjdbc/compare/REL42.3.3...REL42.4.1) --- updated-dependencies: - dependency-name: org.postgresql:postgresql dependency-type: direct:production ... Signed-off-by: dependabot[bot] * Bump postgresql from 42.4.0 to 42.4.1 in /frameworks/Java/undertow Bumps [postgresql](https://github.com/pgjdbc/pgjdbc) from 42.4.0 to 42.4.1. - [Release notes](https://github.com/pgjdbc/pgjdbc/releases) - [Changelog](https://github.com/pgjdbc/pgjdbc/blob/master/CHANGELOG.md) - [Commits](https://github.com/pgjdbc/pgjdbc/compare/REL42.4.0...REL42.4.1) --- updated-dependencies: - dependency-name: org.postgresql:postgresql dependency-type: direct:production ... Signed-off-by: dependabot[bot] * Bump postgresql from 42.2.23 to 42.4.1 in /frameworks/Kotlin/ktor/ktor Bumps [postgresql](https://github.com/pgjdbc/pgjdbc) from 42.2.23 to 42.4.1. - [Release notes](https://github.com/pgjdbc/pgjdbc/releases) - [Changelog](https://github.com/pgjdbc/pgjdbc/blob/master/CHANGELOG.md) - [Commits](https://github.com/pgjdbc/pgjdbc/compare/REL42.2.23...REL42.4.1) --- updated-dependencies: - dependency-name: org.postgresql:postgresql dependency-type: direct:production ... Signed-off-by: dependabot[bot] * Update dependencies * Bump undertow-core in /frameworks/Java/light-java Bumps [undertow-core](https://github.com/undertow-io/undertow) from 2.2.15.Final to 2.2.19.Final. - [Release notes](https://github.com/undertow-io/undertow/releases) - [Commits](https://github.com/undertow-io/undertow/compare/2.2.15.Final...2.2.19.Final) --- updated-dependencies: - dependency-name: io.undertow:undertow-core dependency-type: direct:production ... Signed-off-by: dependabot[bot] * Bump undertow-core in /frameworks/Java/undertow Bumps [undertow-core](https://github.com/undertow-io/undertow) from 2.2.18.Final to 2.2.19.Final. - [Release notes](https://github.com/undertow-io/undertow/releases) - [Commits](https://github.com/undertow-io/undertow/compare/2.2.18.Final...2.2.19.Final) --- updated-dependencies: - dependency-name: io.undertow:undertow-core dependency-type: direct:production ... Signed-off-by: dependabot[bot] * Delete Gradle Wrapper * Use different JSON serializer * Restore non Hexagon files * Update Hexagon version * Run pipeline * Run pipeline * Bump axum-core from 0.2.7 to 0.2.8 in /frameworks/Rust/axum Bumps [axum-core](https://github.com/tokio-rs/axum) from 0.2.7 to 0.2.8. - [Release notes](https://github.com/tokio-rs/axum/releases) - [Changelog](https://github.com/tokio-rs/axum/blob/main/CHANGELOG.md) - [Commits](https://github.com/tokio-rs/axum/compare/axum-core-v0.2.7...axum-core-v0.2.8) --- updated-dependencies: - dependency-name: axum-core dependency-type: indirect ... Signed-off-by: dependabot[bot] * Revert "Bump axum-core from 0.2.7 to 0.2.8 in /frameworks/Rust/axum" This reverts commit 4422de8915e70cdca67a07c2e0fdb0610757924b. * Version updates, code refactor and new benchmark cases * Version updates * Version updates * Version updates * [Hexagon] Refactor and updates: * Update Hexagon version * Use Rocker template * Modularize the different scenarios * Fix connection problems * Update Hexagon * Update Gradle * Update dependencies * Update Hexagon version * Update Gradle Wrapper * Add async and native support * Add async and native support * Add async and native support * Replace Vert.x adapter by Netty Epoll Async adapter * Replace Vert.x adapter by Netty Epoll Async adapter * Replace Vert.x adapter by Netty Epoll Async adapter * Replace Vert.x adapter by Netty Epoll Async adapter * Replace Vert.x adapter by Netty Epoll Async adapter * Add Jasync store * Add Jasync store * Update * Update * Update * Update Gradle * Benchmark Netty Epoll only * Add Nima adapter * Update container builds * Fix missing endpoints * Fix Nima benchmarks * Update dependencies * Update dependencies * Update dependencies * Fix build * Fix controller * Fix native tests * Fix native tests * Add note * Add note * Update dependencies * Update dependencies * Update dependencies * Recheck CI jobs * Update dependencies * Update dependencies * Update dependencies * Update dependencies * Update dependencies * Update dependencies * Update Hexagon and Java version, switch templates to JTE * Update Hexagon and improve Netty Epoll configuration * Update Hexagon version * Update dependencies * Update dependencies * Update dependencies * Update dependencies * Update dependencies * Update dependencies * Update dependencies * Update dependencies * Update dependencies * Update dependencies * Update dependencies * Update dependencies * Update dependencies * Update Hexagon version * Update dependencies --------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- frameworks/Kotlin/hexagon/build.gradle | 14 +++++++------- .../gradle/wrapper/gradle-wrapper.properties | 2 +- .../hexagon/hexagon-helidon-pgclient.dockerfile | 4 ++-- .../Kotlin/hexagon/hexagon-helidon.dockerfile | 4 ++-- .../hexagon/hexagon-jettyloom-pgclient.dockerfile | 4 ++-- .../Kotlin/hexagon/hexagon-jettyloom.dockerfile | 4 ++-- .../hexagon/hexagon-nettyepoll-pgclient.dockerfile | 4 ++-- .../Kotlin/hexagon/hexagon-nettyepoll.dockerfile | 4 ++-- .../Kotlin/hexagon/hexagon-tomcat.dockerfile | 4 ++-- frameworks/Kotlin/hexagon/hexagon.dockerfile | 4 ++-- .../src/main/kotlin/WebListenerServer.kt | 5 +++-- 11 files changed, 27 insertions(+), 26 deletions(-) diff --git a/frameworks/Kotlin/hexagon/build.gradle b/frameworks/Kotlin/hexagon/build.gradle index 9279d3b38fd..a4d141e5c2a 100644 --- a/frameworks/Kotlin/hexagon/build.gradle +++ b/frameworks/Kotlin/hexagon/build.gradle @@ -1,7 +1,7 @@ plugins { - id "org.jetbrains.kotlin.jvm" version "1.9.23" apply false - id "org.graalvm.buildtools.native" version "0.10.1" apply false + id "org.jetbrains.kotlin.jvm" version "2.0.20-RC" apply false + id "org.graalvm.buildtools.native" version "0.10.2" apply false } version = "1.0.0" @@ -9,13 +9,13 @@ description = "TFB benchmark" group = "com.hexagonkt" ext { - hexagonVersion = "3.5.1" - jettyVersion = "12.0.7" - nettyVersion = "4.1.107.Final" + hexagonVersion = "3.6.1" + jettyVersion = "12.0.12" + nettyVersion = "4.1.112.Final" hikariVersion = "5.1.0" postgresqlVersion = "42.7.3" - vertxVersion = "4.5.5" + vertxVersion = "4.5.9" cache2kVersion = "2.6.1.Final" applicationClass = "com.hexagonkt.BenchmarkKt" @@ -30,5 +30,5 @@ subprojects { } tasks.wrapper { - gradleVersion = "8.6" + gradleVersion = "8.9" } diff --git a/frameworks/Kotlin/hexagon/gradle/wrapper/gradle-wrapper.properties b/frameworks/Kotlin/hexagon/gradle/wrapper/gradle-wrapper.properties index a80b22ce5cf..09523c0e549 100644 --- a/frameworks/Kotlin/hexagon/gradle/wrapper/gradle-wrapper.properties +++ b/frameworks/Kotlin/hexagon/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/frameworks/Kotlin/hexagon/hexagon-helidon-pgclient.dockerfile b/frameworks/Kotlin/hexagon/hexagon-helidon-pgclient.dockerfile index d87e78307b0..3b3a1602f55 100644 --- a/frameworks/Kotlin/hexagon/hexagon-helidon-pgclient.dockerfile +++ b/frameworks/Kotlin/hexagon/hexagon-helidon-pgclient.dockerfile @@ -1,7 +1,7 @@ # # BUILD # -FROM docker.io/gradle:8.6-jdk21-alpine AS build +FROM docker.io/gradle:8.9-jdk21-alpine AS build USER root WORKDIR /hexagon @@ -12,7 +12,7 @@ RUN gradle --quiet -x test installDist # # RUNTIME # -FROM docker.io/eclipse-temurin:21-jre-alpine +FROM docker.io/bellsoft/liberica-runtime-container:jre-21-musl ARG PROJECT=hexagon_helidon_pgclient ENV POSTGRESQL_DB_HOST tfb-database diff --git a/frameworks/Kotlin/hexagon/hexagon-helidon.dockerfile b/frameworks/Kotlin/hexagon/hexagon-helidon.dockerfile index 913a9459a06..271fa95dbf8 100644 --- a/frameworks/Kotlin/hexagon/hexagon-helidon.dockerfile +++ b/frameworks/Kotlin/hexagon/hexagon-helidon.dockerfile @@ -1,7 +1,7 @@ # # BUILD # -FROM docker.io/gradle:8.6-jdk21-alpine AS build +FROM docker.io/gradle:8.9-jdk21-alpine AS build USER root WORKDIR /hexagon @@ -12,7 +12,7 @@ RUN gradle --quiet -x test installDist # # RUNTIME # -FROM docker.io/eclipse-temurin:21-jre-alpine +FROM docker.io/bellsoft/liberica-runtime-container:jre-21-musl ARG PROJECT=hexagon_helidon_postgresql ENV POSTGRESQL_DB_HOST tfb-database diff --git a/frameworks/Kotlin/hexagon/hexagon-jettyloom-pgclient.dockerfile b/frameworks/Kotlin/hexagon/hexagon-jettyloom-pgclient.dockerfile index 90d51b0b30b..d6c37bcd77f 100644 --- a/frameworks/Kotlin/hexagon/hexagon-jettyloom-pgclient.dockerfile +++ b/frameworks/Kotlin/hexagon/hexagon-jettyloom-pgclient.dockerfile @@ -1,7 +1,7 @@ # # BUILD # -FROM docker.io/gradle:8.6-jdk21-alpine AS build +FROM docker.io/gradle:8.9-jdk21-alpine AS build USER root WORKDIR /hexagon @@ -12,7 +12,7 @@ RUN gradle --quiet -x test installDist # # RUNTIME # -FROM docker.io/eclipse-temurin:21-jre-alpine +FROM docker.io/bellsoft/liberica-runtime-container:jre-21-musl ARG PROJECT=hexagon_jetty_pgclient ENV POSTGRESQL_DB_HOST tfb-database diff --git a/frameworks/Kotlin/hexagon/hexagon-jettyloom.dockerfile b/frameworks/Kotlin/hexagon/hexagon-jettyloom.dockerfile index 93b0e22a963..07bf482b28e 100644 --- a/frameworks/Kotlin/hexagon/hexagon-jettyloom.dockerfile +++ b/frameworks/Kotlin/hexagon/hexagon-jettyloom.dockerfile @@ -1,7 +1,7 @@ # # BUILD # -FROM docker.io/gradle:8.6-jdk21-alpine AS build +FROM docker.io/gradle:8.9-jdk21-alpine AS build USER root WORKDIR /hexagon @@ -12,7 +12,7 @@ RUN gradle --quiet -x test installDist # # RUNTIME # -FROM docker.io/eclipse-temurin:21-jre-alpine +FROM docker.io/bellsoft/liberica-runtime-container:jre-21-musl ARG PROJECT=hexagon_jetty_postgresql ENV POSTGRESQL_DB_HOST tfb-database diff --git a/frameworks/Kotlin/hexagon/hexagon-nettyepoll-pgclient.dockerfile b/frameworks/Kotlin/hexagon/hexagon-nettyepoll-pgclient.dockerfile index ba9b55020b9..972347f053b 100644 --- a/frameworks/Kotlin/hexagon/hexagon-nettyepoll-pgclient.dockerfile +++ b/frameworks/Kotlin/hexagon/hexagon-nettyepoll-pgclient.dockerfile @@ -1,7 +1,7 @@ # # BUILD # -FROM docker.io/gradle:8.6-jdk21-alpine AS build +FROM docker.io/gradle:8.9-jdk21-alpine AS build USER root WORKDIR /hexagon @@ -12,7 +12,7 @@ RUN gradle --quiet -x test installDist # # RUNTIME # -FROM docker.io/eclipse-temurin:21-jre-alpine +FROM docker.io/bellsoft/liberica-runtime-container:jre-21-musl ARG PROJECT=hexagon_nettyepoll_pgclient ENV POSTGRESQL_DB_HOST tfb-database diff --git a/frameworks/Kotlin/hexagon/hexagon-nettyepoll.dockerfile b/frameworks/Kotlin/hexagon/hexagon-nettyepoll.dockerfile index a7c28730e03..393f73f62a6 100644 --- a/frameworks/Kotlin/hexagon/hexagon-nettyepoll.dockerfile +++ b/frameworks/Kotlin/hexagon/hexagon-nettyepoll.dockerfile @@ -1,7 +1,7 @@ # # BUILD # -FROM docker.io/gradle:8.6-jdk21-alpine AS build +FROM docker.io/gradle:8.9-jdk21-alpine AS build USER root WORKDIR /hexagon @@ -12,7 +12,7 @@ RUN gradle --quiet -x test installDist # # RUNTIME # -FROM docker.io/eclipse-temurin:21-jre-alpine +FROM docker.io/bellsoft/liberica-runtime-container:jre-21-musl ARG PROJECT=hexagon_nettyepoll_postgresql ENV POSTGRESQL_DB_HOST tfb-database diff --git a/frameworks/Kotlin/hexagon/hexagon-tomcat.dockerfile b/frameworks/Kotlin/hexagon/hexagon-tomcat.dockerfile index abd537c0dd3..32e153cbc0a 100644 --- a/frameworks/Kotlin/hexagon/hexagon-tomcat.dockerfile +++ b/frameworks/Kotlin/hexagon/hexagon-tomcat.dockerfile @@ -1,7 +1,7 @@ # # BUILD # -FROM docker.io/gradle:8.6-jdk21-alpine AS build +FROM docker.io/gradle:8.9-jdk21-alpine AS build USER root WORKDIR /hexagon @@ -12,7 +12,7 @@ RUN gradle --quiet -x test war # # RUNTIME # -FROM docker.io/tomcat:10-jre21-temurin-jammy +FROM docker.io/tomcat:11.0.0-jre21-temurin-noble ARG MODULE=/hexagon/hexagon_tomcat_postgresql ENV POSTGRESQL_DB_HOST tfb-database diff --git a/frameworks/Kotlin/hexagon/hexagon.dockerfile b/frameworks/Kotlin/hexagon/hexagon.dockerfile index a8eec2e6809..59f89e5cb5c 100644 --- a/frameworks/Kotlin/hexagon/hexagon.dockerfile +++ b/frameworks/Kotlin/hexagon/hexagon.dockerfile @@ -1,7 +1,7 @@ # # BUILD # -FROM docker.io/gradle:8.6-jdk21-alpine AS build +FROM docker.io/gradle:8.9-jdk21-alpine AS build USER root WORKDIR /hexagon @@ -12,7 +12,7 @@ RUN gradle --quiet -x test installDist # # RUNTIME # -FROM docker.io/eclipse-temurin:21-jre-alpine +FROM docker.io/bellsoft/liberica-runtime-container:jre-21-musl ARG PROJECT=hexagon_jetty_postgresql ENV POSTGRESQL_DB_HOST tfb-database diff --git a/frameworks/Kotlin/hexagon/hexagon_tomcat_postgresql/src/main/kotlin/WebListenerServer.kt b/frameworks/Kotlin/hexagon/hexagon_tomcat_postgresql/src/main/kotlin/WebListenerServer.kt index 69fe6d13ba6..c7d7ea4449c 100644 --- a/frameworks/Kotlin/hexagon/hexagon_tomcat_postgresql/src/main/kotlin/WebListenerServer.kt +++ b/frameworks/Kotlin/hexagon/hexagon_tomcat_postgresql/src/main/kotlin/WebListenerServer.kt @@ -6,6 +6,7 @@ import com.hexagonkt.http.model.Header import com.hexagonkt.http.model.Headers import com.hexagonkt.http.handlers.HttpHandler import com.hexagonkt.http.handlers.OnHandler +import com.hexagonkt.http.handlers.PathHandler import com.hexagonkt.http.server.servlet.ServletServer import com.hexagonkt.store.BenchmarkSqlStore import com.hexagonkt.templates.jte.JteAdapter @@ -18,7 +19,7 @@ import jakarta.servlet.annotation.WebListener private companion object { val headers = Headers(Header("server", "Tomcat")) - fun createHandlers(settings: Settings): List { + fun createHandlers(settings: Settings): HttpHandler { val store = BenchmarkSqlStore("postgresql") val templateEngine = JteAdapter(TEXT_HTML, precompiled = true) val templateUrl = urlOf("classpath:fortunes.jte") @@ -28,7 +29,7 @@ import jakarta.servlet.annotation.WebListener send(headers = headers) } - return listOf(serverHeaderHandler, controllerPath) + return PathHandler(serverHeaderHandler, controllerPath) } } } From ee5d2b2b8574bbe6c805863d1e09367a8927353d Mon Sep 17 00:00:00 2001 From: Andrew McCloskey Date: Thu, 8 Aug 2024 16:05:05 -0400 Subject: [PATCH 059/204] vertx-web-kotlin-dsljson updates (#9192) * minor performance improvements and warning suppression * vertx-web-kotlin-dsljson updates * formatting * update postgres socket connection config --- .../configuration/scripts/server.sh | 12 ++++++------ .../src/main/kotlin/com/example/starter/App.kt | 8 ++++---- .../com/example/starter/PostgresVerticle.kt | 15 ++++----------- .../com/example/starter/db/AbstractRepository.kt | 2 +- .../com/example/starter/db/FortuneRepository.kt | 4 ++-- .../com/example/starter/db/WorldRepository.kt | 10 +++++----- .../com/example/starter/utils/JsonExtensions.kt | 2 +- .../example/starter/utils/PeriodicDateResolver.kt | 7 +++++-- .../com/example/starter/utils/RowSetExtensions.kt | 3 ++- .../example/starter/utils/ThrowableExtensions.kt | 12 ++++++++---- .../src/main/resources/pg-connect-options.json | 5 +---- ...vertx-web-kotlin-dsljson-postgresql.dockerfile | 4 +++- .../vertx-web-kotlin-dsljson.dockerfile | 4 +++- 13 files changed, 45 insertions(+), 43 deletions(-) diff --git a/frameworks/Kotlin/vertx-web-kotlin-dsljson/configuration/scripts/server.sh b/frameworks/Kotlin/vertx-web-kotlin-dsljson/configuration/scripts/server.sh index 80e05662a59..a5b03908062 100644 --- a/frameworks/Kotlin/vertx-web-kotlin-dsljson/configuration/scripts/server.sh +++ b/frameworks/Kotlin/vertx-web-kotlin-dsljson/configuration/scripts/server.sh @@ -1,16 +1,17 @@ #!/bin/bash -NUM_PROCESSORS=$((`grep --count ^processor /proc/cpuinfo`)) - JVM_OPTS="-server \ -Xms2G \ -Xmx2G \ + -XX:+AlwaysPreTouch \ -XX:+UseParallelGC \ + -XX:+PreserveFramePointer \ + -XX:+EnableDynamicAgentLoading \ -XX:InitialCodeCacheSize=512m \ -XX:ReservedCodeCacheSize=512m \ -XX:MaxInlineLevel=20 \ - -XX:+AlwaysPreTouch \ -XX:+UseNUMA \ + -Djava.lang.Integer.IntegerCache.high=10000 \ -Dvertx.disableMetrics=true \ -Dvertx.disableH2c=true \ -Dvertx.disableWebsockets=true \ @@ -19,6 +20,7 @@ JVM_OPTS="-server \ -Dvertx.disableContextTimings=true \ -Dvertx.disableTCCL=true \ -Dvertx.disableHttpHeadersValidation=true \ + -Dvertx.eventLoopPoolSize=$((`grep --count ^processor /proc/cpuinfo`)) \ -Dlog4j2.contextSelector=org.apache.logging.log4j.core.async.AsyncLoggerContextSelector \ -Dio.netty.buffer.checkBounds=false \ -Dio.netty.buffer.checkAccessible=false \ @@ -26,8 +28,6 @@ JVM_OPTS="-server \ JAR_PATH="./build/libs/vertx-web-kotlin-dsljson-benchmark-1.0.0-SNAPSHOT-fat.jar" -VERTX_ARGS="-instances 1" - cleanup() { echo "Caught SIGINT signal. Stopping the Java program..." if [ ! -z "$JAVA_PID" ]; then @@ -39,7 +39,7 @@ cleanup() { trap cleanup SIGINT -java $JVM_OPTS -jar $JAR_PATH $VERTX_ARGS & +java $JVM_OPTS -jar $JAR_PATH & JAVA_PID=$! echo "Server PID: $JAVA_PID" diff --git a/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/App.kt b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/App.kt index 03fb0ca2c04..ee66a635231 100644 --- a/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/App.kt +++ b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/App.kt @@ -3,7 +3,6 @@ package com.example.starter import com.example.starter.utils.PeriodicDateResolver import com.example.starter.utils.block import io.vertx.core.Vertx -import io.vertx.core.impl.cpu.CpuCoreSensor import io.vertx.kotlin.core.deploymentOptionsOf import io.vertx.kotlin.core.vertxOptionsOf import kotlin.time.Duration.Companion.seconds @@ -14,11 +13,12 @@ object App : Logging { @JvmStatic fun main(args: Array?) { - val numCores = CpuCoreSensor.availableProcessors() + val eventLoopPoolSize = System.getProperty("vertx.eventLoopPoolSize")?.toInt() + ?: Runtime.getRuntime().availableProcessors() val vertx = Vertx.vertx( vertxOptionsOf( - eventLoopPoolSize = numCores, + eventLoopPoolSize = eventLoopPoolSize, preferNativeTransport = true, ) ) @@ -41,7 +41,7 @@ object App : Logging { vertx.deployVerticle( { if (hasDb) PostgresVerticle() else BasicVerticle() }, deploymentOptionsOf( - instances = numCores, + instances = eventLoopPoolSize, ) ) diff --git a/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/PostgresVerticle.kt b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/PostgresVerticle.kt index 43cba217ec0..4caa057b488 100644 --- a/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/PostgresVerticle.kt +++ b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/PostgresVerticle.kt @@ -5,10 +5,8 @@ import com.example.starter.db.WorldRepository import com.example.starter.handlers.FortuneHandler import com.example.starter.handlers.WorldHandler import com.example.starter.io.JsonResource -import com.example.starter.utils.array import com.example.starter.utils.isConnectionReset import io.vertx.core.AbstractVerticle -import io.vertx.core.Future import io.vertx.core.Promise import io.vertx.core.http.HttpServerOptions import io.vertx.ext.web.Router @@ -18,15 +16,10 @@ import org.apache.logging.log4j.kotlin.Logging class PostgresVerticle : AbstractVerticle() { override fun start(startPromise: Promise) { - Future.all( - PgConnection.connect(vertx, PG_CONNECT_OPTIONS), - PgConnection.connect(vertx, PG_CONNECT_OPTIONS), - ) - .onSuccess { cf -> - val pool = cf.array() - - val fortuneHandler = FortuneHandler(FortuneRepository(pool)) - val worldHandler = WorldHandler(WorldRepository(pool)) + PgConnection.connect(vertx, PG_CONNECT_OPTIONS) + .onSuccess { conn -> + val fortuneHandler = FortuneHandler(FortuneRepository(conn)) + val worldHandler = WorldHandler(WorldRepository(conn)) val router = Router.router(vertx) diff --git a/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/db/AbstractRepository.kt b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/db/AbstractRepository.kt index df665df0769..f2dec9a5f84 100644 --- a/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/db/AbstractRepository.kt +++ b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/db/AbstractRepository.kt @@ -3,5 +3,5 @@ package com.example.starter.db import io.vertx.pgclient.PgConnection abstract class AbstractRepository( - protected val pool: Array + protected val conn: PgConnection ) \ No newline at end of file diff --git a/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/db/FortuneRepository.kt b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/db/FortuneRepository.kt index 3bb95576a4d..b9e4b9ab784 100644 --- a/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/db/FortuneRepository.kt +++ b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/db/FortuneRepository.kt @@ -7,8 +7,8 @@ import io.vertx.core.Future import io.vertx.pgclient.PgConnection import io.vertx.sqlclient.Row -class FortuneRepository(pool: Array) : AbstractRepository(pool) { - private val selectFortuneQuery = this.pool[0].preparedQuery(SELECT_FORTUNE_SQL) +class FortuneRepository(conn: PgConnection) : AbstractRepository(conn) { + private val selectFortuneQuery = this.conn.preparedQuery(SELECT_FORTUNE_SQL) fun selectFortunes(): Future> = selectFortuneQuery .execute() diff --git a/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/db/WorldRepository.kt b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/db/WorldRepository.kt index 734b486547a..74823141453 100644 --- a/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/db/WorldRepository.kt +++ b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/db/WorldRepository.kt @@ -13,10 +13,10 @@ import io.vertx.sqlclient.impl.SqlClientInternal import java.util.concurrent.ThreadLocalRandom import java.util.concurrent.atomic.AtomicInteger -@Suppress("NOTHING_TO_INLINE") -class WorldRepository(pool: Array) : AbstractRepository(pool) { - private val selectWorldQuery = this.pool[0].preparedQuery(SELECT_WORLD_SQL) - private val updateWorldQueries = generateQueries(this.pool[1]) +@Suppress("NOTHING_TO_INLINE", "UNCHECKED_CAST") +class WorldRepository(conn: PgConnection) : AbstractRepository(conn) { + private val selectWorldQuery = this.conn.preparedQuery(SELECT_WORLD_SQL) + private val updateWorldQueries = generateQueries(this.conn) fun selectRandomWorld(): Future = selectWorldQuery .execute(Tuple.of(randomWorld())) @@ -26,7 +26,7 @@ class WorldRepository(pool: Array) : AbstractRepository(poo val promise = Promise.promise>() val arr = arrayOfNulls(numWorlds) val count = AtomicInteger(0) - (this.pool[0] as SqlClientInternal).group { c -> + (this.conn as SqlClientInternal).group { c -> repeat(numWorlds) { c.preparedQuery(SELECT_WORLD_SQL).execute(Tuple.of(randomWorld())) { ar -> val index = count.getAndIncrement() diff --git a/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/utils/JsonExtensions.kt b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/utils/JsonExtensions.kt index 87c965ca9b7..264be5a7323 100644 --- a/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/utils/JsonExtensions.kt +++ b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/utils/JsonExtensions.kt @@ -16,4 +16,4 @@ inline fun T.serialize(initialSizeHint: Int = 0): Buffer { val output = BufferOutputStream(initialSizeHint) DSL_JSON.serialize(this, output) return output -} \ No newline at end of file +} diff --git a/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/utils/PeriodicDateResolver.kt b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/utils/PeriodicDateResolver.kt index 2e29e784914..23786587569 100644 --- a/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/utils/PeriodicDateResolver.kt +++ b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/utils/PeriodicDateResolver.kt @@ -1,16 +1,19 @@ package com.example.starter.utils import io.vertx.core.Vertx +import io.vertx.core.http.HttpHeaders import java.time.ZonedDateTime import java.time.format.DateTimeFormatter object PeriodicDateResolver { - var current: String = next() + var current: CharSequence = next() fun init(vertx: Vertx) { vertx.setPeriodic(1000L) { current = next() } } @Suppress("NOTHING_TO_INLINE") - private inline fun next(): String = DateTimeFormatter.RFC_1123_DATE_TIME.format(ZonedDateTime.now()) + private inline fun next(): CharSequence = HttpHeaders.createOptimized( + DateTimeFormatter.RFC_1123_DATE_TIME.format(ZonedDateTime.now()) + ) } \ No newline at end of file diff --git a/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/utils/RowSetExtensions.kt b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/utils/RowSetExtensions.kt index c968777ff77..3959ba8d9a0 100644 --- a/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/utils/RowSetExtensions.kt +++ b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/utils/RowSetExtensions.kt @@ -5,10 +5,11 @@ import io.vertx.sqlclient.RowSet // This extension relies on the assumption the mapper never returns null, as it is defined. Otherwise, // we prevent the overhead from having to do another iteration over the loop for a `filterNotNull` check. +@Suppress("UNCHECKED_CAST") inline fun RowSet.mapToArray(mapper: (Row) -> U): Array { val arr = arrayOfNulls(this.size()) val iterator = this.iterator() var index = 0 while (iterator.hasNext()) arr[index++] = mapper(iterator.next()) return arr as Array -} \ No newline at end of file +} diff --git a/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/utils/ThrowableExtensions.kt b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/utils/ThrowableExtensions.kt index 044d24b06ab..00cf1463297 100644 --- a/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/utils/ThrowableExtensions.kt +++ b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/utils/ThrowableExtensions.kt @@ -6,7 +6,11 @@ import java.net.SocketException const val CONNECTION_RESET_MESSAGE = "Connection reset" -fun Throwable.isConnectionReset(): Boolean { - return (this is NativeIoException && this.expectedErr() == Errors.ERRNO_ECONNRESET_NEGATIVE) - || (this is SocketException && this.message == CONNECTION_RESET_MESSAGE) -} \ No newline at end of file +@Suppress("NOTHING_TO_INLINE") +inline fun Throwable.isConnectionReset(): Boolean { + return when { + this is NativeIoException && this.expectedErr() == Errors.ERRNO_ECONNRESET_NEGATIVE -> true + this is SocketException && this.message == CONNECTION_RESET_MESSAGE -> true + else -> false + } +} diff --git a/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/resources/pg-connect-options.json b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/resources/pg-connect-options.json index a145a0a51c5..3cf43317687 100644 --- a/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/resources/pg-connect-options.json +++ b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/resources/pg-connect-options.json @@ -5,10 +5,7 @@ "port": 5432, "database": "hello_world", "cachePreparedStatements": true, - "preparedStatementCacheMaxSize": 512, - "preparedStatementCacheSqlLimit": 2048, - "tcpKeepAlive": true, - "tcpFastOpen": true, + "preparedStatementCacheMaxSize": 1024, "pipeliningLimit": 100000, "receiveBufferSize": 262144, "sendBufferSize": 262144 diff --git a/frameworks/Kotlin/vertx-web-kotlin-dsljson/vertx-web-kotlin-dsljson-postgresql.dockerfile b/frameworks/Kotlin/vertx-web-kotlin-dsljson/vertx-web-kotlin-dsljson-postgresql.dockerfile index 0ef28c410d9..50152d8df30 100644 --- a/frameworks/Kotlin/vertx-web-kotlin-dsljson/vertx-web-kotlin-dsljson-postgresql.dockerfile +++ b/frameworks/Kotlin/vertx-web-kotlin-dsljson/vertx-web-kotlin-dsljson-postgresql.dockerfile @@ -17,10 +17,11 @@ CMD java \ -Xmx2G \ -XX:+AlwaysPreTouch \ -XX:+UseParallelGC \ - -XX:InitialCodeCacheSize=512m \ + -XX:InitialCodeCacheSize=512m \ -XX:ReservedCodeCacheSize=512m \ -XX:MaxInlineLevel=20 \ -XX:+UseNUMA \ + -Djava.lang.Integer.IntegerCache.high=10000 \ -Dvertx.disableMetrics=true \ -Dvertx.disableH2c=true \ -Dvertx.disableWebsockets=true \ @@ -29,6 +30,7 @@ CMD java \ -Dvertx.disableContextTimings=true \ -Dvertx.disableTCCL=true \ -Dvertx.disableHttpHeadersValidation=true \ + -Dvertx.eventLoopPoolSize=$((`grep --count ^processor /proc/cpuinfo`)) \ -Dlog4j2.contextSelector=org.apache.logging.log4j.core.async.AsyncLoggerContextSelector \ -Dio.netty.buffer.checkBounds=false \ -Dio.netty.buffer.checkAccessible=false \ diff --git a/frameworks/Kotlin/vertx-web-kotlin-dsljson/vertx-web-kotlin-dsljson.dockerfile b/frameworks/Kotlin/vertx-web-kotlin-dsljson/vertx-web-kotlin-dsljson.dockerfile index a4a1c142cf5..568f19f79dd 100644 --- a/frameworks/Kotlin/vertx-web-kotlin-dsljson/vertx-web-kotlin-dsljson.dockerfile +++ b/frameworks/Kotlin/vertx-web-kotlin-dsljson/vertx-web-kotlin-dsljson.dockerfile @@ -17,10 +17,11 @@ CMD java \ -Xmx2G \ -XX:+AlwaysPreTouch \ -XX:+UseParallelGC \ - -XX:InitialCodeCacheSize=512m \ + -XX:InitialCodeCacheSize=512m \ -XX:ReservedCodeCacheSize=512m \ -XX:MaxInlineLevel=20 \ -XX:+UseNUMA \ + -Djava.lang.Integer.IntegerCache.high=10000 \ -Dvertx.disableMetrics=true \ -Dvertx.disableH2c=true \ -Dvertx.disableWebsockets=true \ @@ -29,6 +30,7 @@ CMD java \ -Dvertx.disableContextTimings=true \ -Dvertx.disableTCCL=true \ -Dvertx.disableHttpHeadersValidation=true \ + -Dvertx.eventLoopPoolSize=$((`grep --count ^processor /proc/cpuinfo`)) \ -Dlog4j2.contextSelector=org.apache.logging.log4j.core.async.AsyncLoggerContextSelector \ -Dio.netty.buffer.checkBounds=false \ -Dio.netty.buffer.checkAccessible=false \ From 2e05f43beb2bdbf2dffa80b0bfadb584e21793a9 Mon Sep 17 00:00:00 2001 From: Francesco Iapicca Date: Thu, 8 Aug 2024 23:06:20 +0300 Subject: [PATCH 060/204] Add Dart 3 example (#9197) * port dart2 implementation * somehow stable version of dart in docker is not 3.5.0 yet, reverting pubspec and dockerfile * general code clean up * update dockerfile * update server binding * change InternetAddress in binging to string * re-bump to dart 3.5 * fix error in server.dart * rename Containerfile as dart3.dockerfile --------- Co-authored-by: Francesco Iapicca --- frameworks/Dart/dart3/.dockerignore | 9 +++ frameworks/Dart/dart3/.gitignore | 5 ++ frameworks/Dart/dart3/README.md | 22 +++++ frameworks/Dart/dart3/analysis_options.yaml | 1 + frameworks/Dart/dart3/benchmark_config.json | 26 ++++++ frameworks/Dart/dart3/bin/server.dart | 89 +++++++++++++++++++++ frameworks/Dart/dart3/dart3.dockerfile | 14 ++++ frameworks/Dart/dart3/pubspec.yaml | 7 ++ 8 files changed, 173 insertions(+) create mode 100644 frameworks/Dart/dart3/.dockerignore create mode 100644 frameworks/Dart/dart3/.gitignore create mode 100644 frameworks/Dart/dart3/README.md create mode 100644 frameworks/Dart/dart3/analysis_options.yaml create mode 100644 frameworks/Dart/dart3/benchmark_config.json create mode 100755 frameworks/Dart/dart3/bin/server.dart create mode 100644 frameworks/Dart/dart3/dart3.dockerfile create mode 100644 frameworks/Dart/dart3/pubspec.yaml diff --git a/frameworks/Dart/dart3/.dockerignore b/frameworks/Dart/dart3/.dockerignore new file mode 100644 index 00000000000..6a6cc8727a7 --- /dev/null +++ b/frameworks/Dart/dart3/.dockerignore @@ -0,0 +1,9 @@ +# From https://hub.docker.com/_/dart +.dockerignore +Dockerfile +build/ +.dart_tool/ +.git/ +.github/ +.gitignore +.packages diff --git a/frameworks/Dart/dart3/.gitignore b/frameworks/Dart/dart3/.gitignore new file mode 100644 index 00000000000..8ac40f21809 --- /dev/null +++ b/frameworks/Dart/dart3/.gitignore @@ -0,0 +1,5 @@ +# https://dart.dev/guides/libraries/private-files +# Created by `dart pub` +.dart_tool/ +*.lock +!bin \ No newline at end of file diff --git a/frameworks/Dart/dart3/README.md b/frameworks/Dart/dart3/README.md new file mode 100644 index 00000000000..7152e705637 --- /dev/null +++ b/frameworks/Dart/dart3/README.md @@ -0,0 +1,22 @@ +# Dart 3 Benchmarking Test + +### Test Type Implementation Source Code + +- [JSON](server.dart) +- [PLAINTEXT](server.dart) + +## Important Libraries + +The tests were run with: + +- [Dart v3.4.4](https://dart.dev/) + +## Test URLs + +### JSON + +http://localhost:8080/json + +### PLAINTEXT + +http://localhost:8080/plaintext diff --git a/frameworks/Dart/dart3/analysis_options.yaml b/frameworks/Dart/dart3/analysis_options.yaml new file mode 100644 index 00000000000..572dd239d09 --- /dev/null +++ b/frameworks/Dart/dart3/analysis_options.yaml @@ -0,0 +1 @@ +include: package:lints/recommended.yaml diff --git a/frameworks/Dart/dart3/benchmark_config.json b/frameworks/Dart/dart3/benchmark_config.json new file mode 100644 index 00000000000..059fb368d0e --- /dev/null +++ b/frameworks/Dart/dart3/benchmark_config.json @@ -0,0 +1,26 @@ +{ + "framework": "dart3", + "tests": [ + { + "default": { + "json_url": "/json", + "plaintext_url": "/plaintext", + "port": 8080, + "approach": "Stripped", + "classification": "Platform", + "database": "None", + "framework": "None", + "language": "Dart", + "flavor": "None", + "orm": "None", + "platform": "None", + "webserver": "None", + "os": "Linux", + "database_os": "Linux", + "display_name": "dart3", + "notes": "", + "versus": "None" + } + } + ] +} diff --git a/frameworks/Dart/dart3/bin/server.dart b/frameworks/Dart/dart3/bin/server.dart new file mode 100755 index 00000000000..f2b98dcd197 --- /dev/null +++ b/frameworks/Dart/dart3/bin/server.dart @@ -0,0 +1,89 @@ +import 'dart:convert'; +import 'dart:io'; +import 'dart:isolate'; + +final _encoder = JsonUtf8Encoder(); + +void main(List _) async { + /// Create an [Isolate] containinig an [HttpServer] + /// for each processor after the first + for (var i = 1; i < Platform.numberOfProcessors; i++) { + await Isolate.spawn(_startServer, _); + } + + /// Create a [HttpServer] for the first processor + await _startServer(_); +} + +/// Creates and setup a [HttpServer] +Future _startServer(List _) async { + /// Binds the [HttpServer] on `0.0.0.0:8080`. + final server = await HttpServer.bind( + InternetAddress('0.0.0.0', type: InternetAddressType.IPv4), + 8080, + shared: true, + ); + + /// Sets [HttpServer]'s [serverHeader]. + server + ..defaultResponseHeaders.clear() + ..serverHeader = 'dart'; + + /// Handles [HttpRequest]'s from [HttpServer]. + await for (final request in server) { + switch (request.uri.path) { + case '/json': + _jsonTest(request); + break; + case '/plaintext': + _plaintextTest(request); + break; + default: + _sendResponse(request, HttpStatus.notFound); + } + } +} + +/// Completes the given [request] by writing the [bytes] with the given +/// [statusCode] and [type]. +void _sendResponse( + HttpRequest request, + int statusCode, { + ContentType? type, + List bytes = const [], +}) => + request.response + ..statusCode = statusCode + ..headers.contentType = type + ..headers.date = DateTime.now() + ..contentLength = bytes.length + ..add(bytes) + ..close(); + +/// Completes the given [request] by writing the [response] as JSON. +void _sendJson(HttpRequest request, Object response) => _sendResponse( + request, + HttpStatus.ok, + type: ContentType.json, + bytes: _encoder.convert(response), + ); + +/// Completes the given [request] by writing the [response] as plain text. +void _sendText(HttpRequest request, String response) => _sendResponse( + request, + HttpStatus.ok, + type: ContentType.text, + bytes: utf8.encode(response), + ); + +/// Responds with the JSON test to the [request]. +void _jsonTest(HttpRequest request) => _sendJson( + request, + const {'message': 'Hello, World!'}, + ); + +/// Responds with the plaintext test to the [request]. +void _plaintextTest(HttpRequest request) => _sendText( + request, + 'Hello, World!', + ); diff --git a/frameworks/Dart/dart3/dart3.dockerfile b/frameworks/Dart/dart3/dart3.dockerfile new file mode 100644 index 00000000000..7e6e9053968 --- /dev/null +++ b/frameworks/Dart/dart3/dart3.dockerfile @@ -0,0 +1,14 @@ + +FROM dart:3.5 AS builder + +COPY . /app +WORKDIR /app +RUN mkdir build +RUN dart compile exe ./bin/server.dart -o build/server + +FROM scratch +COPY --from=builder /runtime/ / +COPY --from=builder /app/build /bin + +EXPOSE 8080 +CMD ["server"] \ No newline at end of file diff --git a/frameworks/Dart/dart3/pubspec.yaml b/frameworks/Dart/dart3/pubspec.yaml new file mode 100644 index 00000000000..2b351720c9b --- /dev/null +++ b/frameworks/Dart/dart3/pubspec.yaml @@ -0,0 +1,7 @@ +name: dartbenchmark +description: A benchmark of dart +environment: + sdk: '>=3.5.0 <4.0.0' + +dev_dependencies: + lints: ^4.0.0 From 3d5d29ef7d557a2cb5e843a97c610bff0e96b9f2 Mon Sep 17 00:00:00 2001 From: Joan Miquel Date: Thu, 8 Aug 2024 22:06:31 +0200 Subject: [PATCH 061/204] [php] Laravel update to v 11 (#9200) * Update Laravel to v 11 * Update and clean dockerfiles * Fix pecl * Update dockerfile and remove extra composer.json * Clean dockerfile --- frameworks/PHP/laravel/composer.json | 2 +- frameworks/PHP/laravel/deploy/conf/php.ini | 2 +- .../laravel/deploy/workerman/composer.json | 58 ------------------- .../PHP/laravel/laravel-laravel-s.dockerfile | 6 +- .../laravel-octane-frankenphp.dockerfile | 26 ++++----- .../PHP/laravel/laravel-roadrunner.dockerfile | 6 +- .../PHP/laravel/laravel-swoole.dockerfile | 6 +- .../PHP/laravel/laravel-workerman.dockerfile | 24 ++++---- frameworks/PHP/laravel/laravel.dockerfile | 21 +++---- 9 files changed, 54 insertions(+), 97 deletions(-) delete mode 100644 frameworks/PHP/laravel/deploy/workerman/composer.json diff --git a/frameworks/PHP/laravel/composer.json b/frameworks/PHP/laravel/composer.json index 094026428e5..f25952eccea 100644 --- a/frameworks/PHP/laravel/composer.json +++ b/frameworks/PHP/laravel/composer.json @@ -8,7 +8,7 @@ ], "license": "MIT", "require": { - "laravel/framework": "^10" + "laravel/framework": "^11" }, "config": { "optimize-autoloader": true, diff --git a/frameworks/PHP/laravel/deploy/conf/php.ini b/frameworks/PHP/laravel/deploy/conf/php.ini index 82133535145..98e34225e0d 100644 --- a/frameworks/PHP/laravel/deploy/conf/php.ini +++ b/frameworks/PHP/laravel/deploy/conf/php.ini @@ -1767,7 +1767,7 @@ ldap.max_links = -1 opcache.enable=1 ; Determines if Zend OPCache is enabled for the CLI version of PHP -;opcache.enable_cli=0 +opcache.enable_cli=1 ; The OPcache shared memory storage size. ;opcache.memory_consumption=128 diff --git a/frameworks/PHP/laravel/deploy/workerman/composer.json b/frameworks/PHP/laravel/deploy/workerman/composer.json deleted file mode 100644 index 343ff8fcf3c..00000000000 --- a/frameworks/PHP/laravel/deploy/workerman/composer.json +++ /dev/null @@ -1,58 +0,0 @@ -{ - "name": "laravel/laravel", - "type": "project", - "description": "The Laravel Framework.", - "keywords": [ - "framework", - "laravel" - ], - "license": "MIT", - "require": { - "php": "^8.0", - "laravel/framework": "^8.0", - "joanhey/adapterman": "^0.6" - }, - "require-dev": { - "facade/ignition": "^2.3.6", - "fzaninotto/faker": "^1.9.1", - "mockery/mockery": "^1.3.1", - "nunomaduro/collision": "^5.0", - "phpunit/phpunit": "^9.3" - }, - "config": { - "optimize-autoloader": true, - "preferred-install": "dist", - "sort-packages": true - }, - "extra": { - "laravel": { - "dont-discover": [] - } - }, - "autoload": { - "psr-4": { - "App\\": "app/" - } - }, - "autoload-dev": { - "psr-4": { - "Tests\\": "tests/" - } - }, - "minimum-stability": "dev", - "prefer-stable": true, - "scripts": { - "post-autoload-dump": [ - "Illuminate\\Foundation\\ComposerScripts::postAutoloadDump", - "@php artisan package:discover --ansi" - ], - "post-root-package-install": [ - "@php -r \"file_exists('.env') || copy('.env.example', '.env');\"" - ], - "post-create-project-cmd": [ - "@php artisan key:generate --ansi" - ] - } -} - - diff --git a/frameworks/PHP/laravel/laravel-laravel-s.dockerfile b/frameworks/PHP/laravel/laravel-laravel-s.dockerfile index a0e946e5097..c353ef28b4f 100644 --- a/frameworks/PHP/laravel/laravel-laravel-s.dockerfile +++ b/frameworks/PHP/laravel/laravel-laravel-s.dockerfile @@ -9,7 +9,11 @@ RUN echo "opcache.jit_buffer_size=128M" >> /usr/local/etc/php/conf.d/docker-php- WORKDIR /laravel COPY --link . . -RUN mkdir -p /laravel/bootstrap/cache /laravel/storage/logs /laravel/storage/framework/sessions /laravel/storage/framework/views /laravel/storage/framework/cache +RUN mkdir -p bootstrap/cache \ + storage/logs \ + storage/framework/sessions \ + storage/framework/views \ + storage/framework/cache COPY --link deploy/laravel-s/composer.json . diff --git a/frameworks/PHP/laravel/laravel-octane-frankenphp.dockerfile b/frameworks/PHP/laravel/laravel-octane-frankenphp.dockerfile index 1829a4292f4..2ad30a612e3 100644 --- a/frameworks/PHP/laravel/laravel-octane-frankenphp.dockerfile +++ b/frameworks/PHP/laravel/laravel-octane-frankenphp.dockerfile @@ -1,25 +1,25 @@ FROM dunglas/frankenphp RUN install-php-extensions \ - pcntl \ + intl \ + opcache \ + pcntl \ pdo_mysql \ - intl \ - zip \ - opcache > /dev/null + zip > /dev/null -COPY . /app +COPY --link . /app/ -COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer +COPY --from=composer --link /usr/bin/composer /usr/local/bin/composer -RUN mkdir -p /app/bootstrap/cache /app/storage/logs /app/storage/framework/sessions /app/storage/framework/views /app/storage/framework/cache -RUN chmod -R 777 /app +RUN mkdir -p bootstrap/cache \ + storage/logs \ + storage/framework/sessions \ + storage/framework/views \ + storage/framework/cache -COPY deploy/conf/php.ini /usr/local/etc/php - -RUN composer require laravel/octane guzzlehttp/guzzle - -RUN composer install --optimize-autoloader --classmap-authoritative --no-dev --quiet +COPY --link deploy/conf/php.ini /usr/local/etc/php +RUN composer require laravel/octane guzzlehttp/guzzle --update-no-dev --no-scripts --quiet RUN php artisan optimize RUN frankenphp -v diff --git a/frameworks/PHP/laravel/laravel-roadrunner.dockerfile b/frameworks/PHP/laravel/laravel-roadrunner.dockerfile index d5d42d62879..33c7067c7b0 100644 --- a/frameworks/PHP/laravel/laravel-roadrunner.dockerfile +++ b/frameworks/PHP/laravel/laravel-roadrunner.dockerfile @@ -9,7 +9,11 @@ RUN echo "opcache.enable_cli=1" >> /usr/local/etc/php/conf.d/docker-php-ext-opca WORKDIR /laravel COPY --link . . -RUN mkdir -p /laravel/bootstrap/cache /laravel/storage/logs /laravel/storage/framework/sessions /laravel/storage/framework/views /laravel/storage/framework/cache +RUN mkdir -p bootstrap/cache \ + storage/logs \ + storage/framework/sessions \ + storage/framework/views \ + storage/framework/cache RUN apt-get update > /dev/null && \ apt-get install -yqq curl unzip > /dev/null diff --git a/frameworks/PHP/laravel/laravel-swoole.dockerfile b/frameworks/PHP/laravel/laravel-swoole.dockerfile index 3882a7ac4c8..52308a4dd5e 100644 --- a/frameworks/PHP/laravel/laravel-swoole.dockerfile +++ b/frameworks/PHP/laravel/laravel-swoole.dockerfile @@ -9,7 +9,11 @@ RUN echo "opcache.jit_buffer_size=128M" >> /usr/local/etc/php/conf.d/docker-php- WORKDIR /laravel COPY --link . . -RUN mkdir -p /laravel/bootstrap/cache /laravel/storage/framework/sessions /laravel/storage/framework/views /laravel/storage/framework/cache +RUN mkdir -p bootstrap/cache \ + storage/logs \ + storage/framework/sessions \ + storage/framework/views \ + storage/framework/cache COPY --link deploy/swoole/composer.json . diff --git a/frameworks/PHP/laravel/laravel-workerman.dockerfile b/frameworks/PHP/laravel/laravel-workerman.dockerfile index 48cf4ee5e42..34ee2de30a5 100644 --- a/frameworks/PHP/laravel/laravel-workerman.dockerfile +++ b/frameworks/PHP/laravel/laravel-workerman.dockerfile @@ -1,4 +1,4 @@ -FROM ubuntu:22.04 +FROM ubuntu:24.04 ARG DEBIAN_FRONTEND=noninteractive @@ -9,23 +9,25 @@ RUN LC_ALL=C.UTF-8 add-apt-repository ppa:ondrej/php > /dev/null && \ RUN apt-get install -yqq git unzip \ php8.3-cli php8.3-mysql php8.3-mbstring php8.3-xml php8.3-curl > /dev/null -COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer +COPY --from=composer --link /usr/bin/composer /usr/local/bin/composer RUN apt-get install -y php-pear php8.3-dev libevent-dev > /dev/null RUN pecl install event-3.1.3 > /dev/null && echo "extension=event.so" > /etc/php/8.3/cli/conf.d/event.ini -ADD ./ /laravel WORKDIR /laravel +COPY --link . . -EXPOSE 8080 - -RUN mkdir -p /laravel/bootstrap/cache /laravel/storage/logs /laravel/storage/framework/sessions /laravel/storage/framework/views /laravel/storage/framework/cache -RUN chmod -R 777 /laravel +RUN mkdir -p bootstrap/cache \ + storage/logs \ + storage/framework/sessions \ + storage/framework/views \ + storage/framework/cache -COPY deploy/workerman/composer.json ./ -RUN composer install --optimize-autoloader --classmap-authoritative --no-dev --quiet +RUN composer require joanhey/adapterman --update-no-dev --no-scripts --quiet RUN php artisan optimize -COPY deploy/conf/cli-php.ini /etc/php/8.3/cli/php.ini +COPY --link deploy/conf/cli-php.ini /etc/php/8.3/cli/php.ini + +EXPOSE 8080 -CMD php server-man.php start +ENTRYPOINT [ "php", "server-man.php", "start" ] diff --git a/frameworks/PHP/laravel/laravel.dockerfile b/frameworks/PHP/laravel/laravel.dockerfile index c1858216a66..455d2e6d60f 100644 --- a/frameworks/PHP/laravel/laravel.dockerfile +++ b/frameworks/PHP/laravel/laravel.dockerfile @@ -1,4 +1,4 @@ -FROM ubuntu:22.04 +FROM ubuntu:24.04 ARG DEBIAN_FRONTEND=noninteractive @@ -7,19 +7,21 @@ RUN LC_ALL=C.UTF-8 add-apt-repository ppa:ondrej/php > /dev/null && \ apt-get update -yqq > /dev/null && apt-get upgrade -yqq > /dev/null RUN apt-get install -yqq nginx git unzip \ - php8.3-cli php8.3-fpm php8.3-mysql php8.3-mbstring php8.3-xml php8.3-dev > /dev/null + php8.3-cli php8.3-fpm php8.3-mysql php8.3-mbstring php8.3-xml php8.3-curl > /dev/null -COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer +COPY --from=composer --link /usr/bin/composer /usr/local/bin/composer -COPY deploy/conf/* /etc/php/8.3/fpm/ - -ADD ./ /laravel +COPY --link deploy/conf/* /etc/php/8.3/fpm/ WORKDIR /laravel +COPY --link . . RUN if [ $(nproc) = 2 ]; then sed -i "s|pm.max_children = 1024|pm.max_children = 512|g" /etc/php/8.3/fpm/php-fpm.conf ; fi; -RUN mkdir -p /laravel/bootstrap/cache /laravel/storage/logs /laravel/storage/framework/sessions /laravel/storage/framework/views /laravel/storage/framework/cache -RUN chmod -R 777 /laravel +RUN mkdir -p bootstrap/cache \ + storage/logs \ + storage/framework/sessions \ + storage/framework/views \ + storage/framework/cache RUN composer install --optimize-autoloader --classmap-authoritative --no-dev --quiet RUN php artisan optimize @@ -29,6 +31,5 @@ EXPOSE 8080 # Uncomment next line for Laravel console error logging to be viewable in docker logs # RUN echo "catch_workers_output = yes" >> /etc/php/8.3/fpm/php-fpm.conf -RUN mkdir -p /run/php -CMD /usr/sbin/php-fpm8.3 --fpm-config /etc/php/8.3/fpm/php-fpm.conf && \ +CMD service php8.3-fpm start && \ nginx -c /laravel/deploy/nginx.conf From 4408f2eade47d7fee8e00a69544a1b3a35d54251 Mon Sep 17 00:00:00 2001 From: Joan Miquel Date: Thu, 8 Aug 2024 22:06:41 +0200 Subject: [PATCH 062/204] [php] Lumen update to v11 (#9199) * Update lumen to v11 * Update and clean dockerfiles --- frameworks/PHP/lumen/composer.json | 2 +- frameworks/PHP/lumen/lumen-laravel-s.dockerfile | 9 +++++++-- frameworks/PHP/lumen/lumen-swoole.dockerfile | 2 +- frameworks/PHP/lumen/lumen-workerman.dockerfile | 13 +++++++------ frameworks/PHP/lumen/lumen.dockerfile | 13 +++++++------ 5 files changed, 23 insertions(+), 16 deletions(-) diff --git a/frameworks/PHP/lumen/composer.json b/frameworks/PHP/lumen/composer.json index aaf2e3d44d1..2552d9450e3 100644 --- a/frameworks/PHP/lumen/composer.json +++ b/frameworks/PHP/lumen/composer.json @@ -5,7 +5,7 @@ "license": "MIT", "type": "project", "require": { - "laravel/lumen-framework": "^10" + "laravel/lumen-framework": "^11" }, "autoload": { "psr-4": { diff --git a/frameworks/PHP/lumen/lumen-laravel-s.dockerfile b/frameworks/PHP/lumen/lumen-laravel-s.dockerfile index a2b4be68310..9c2df7afaef 100644 --- a/frameworks/PHP/lumen/lumen-laravel-s.dockerfile +++ b/frameworks/PHP/lumen/lumen-laravel-s.dockerfile @@ -7,9 +7,14 @@ RUN echo "opcache.enable_cli=1" >> /usr/local/etc/php/conf.d/docker-php-ext-opca #RUN echo "opcache.jit_buffer_size=128M" >> /usr/local/etc/php/conf.d/docker-php-ext-opcache.ini WORKDIR /lumen -ADD --link . . +COPY --link . . + +RUN mkdir -p bootstrap/cache \ + storage/logs \ + storage/framework/sessions \ + storage/framework/views \ + storage/framework/cache -RUN mkdir -p /lumen/bootstrap/cache /lumen/storage/logs /lumen/storage/framework/sessions /lumen/storage/framework/views /lumen/storage/framework/cache RUN chmod -R 777 /lumen COPY deploy/laravel-s/composer.json ./ diff --git a/frameworks/PHP/lumen/lumen-swoole.dockerfile b/frameworks/PHP/lumen/lumen-swoole.dockerfile index de3d4294973..0f4f3434e37 100644 --- a/frameworks/PHP/lumen/lumen-swoole.dockerfile +++ b/frameworks/PHP/lumen/lumen-swoole.dockerfile @@ -3,7 +3,7 @@ FROM phpswoole/swoole:5.1.3-php8.3 RUN docker-php-ext-install pcntl opcache curl > /dev/null WORKDIR /lumen -ADD --link . . +COPY --link . . COPY --link deploy/swoole/php.ini /usr/local/etc/php/ diff --git a/frameworks/PHP/lumen/lumen-workerman.dockerfile b/frameworks/PHP/lumen/lumen-workerman.dockerfile index aabe520cdc8..decfe424411 100644 --- a/frameworks/PHP/lumen/lumen-workerman.dockerfile +++ b/frameworks/PHP/lumen/lumen-workerman.dockerfile @@ -1,4 +1,4 @@ -FROM ubuntu:22.04 +FROM ubuntu:24.04 ARG DEBIAN_FRONTEND=noninteractive @@ -14,16 +14,17 @@ COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer RUN apt-get install -y php-pear php8.3-dev libevent-dev > /dev/null RUN pecl install event-3.1.3 > /dev/null && echo "extension=event.so" > /etc/php/8.3/cli/conf.d/event.ini -ADD ./ /lumen WORKDIR /lumen +COPY --link . . + RUN composer install --optimize-autoloader --classmap-authoritative --no-dev --quiet RUN composer require joanhey/adapterman:^0.6 --quiet -RUN mkdir -p /lumen/storage -RUN mkdir -p /lumen/storage/framework/sessions -RUN mkdir -p /lumen/storage/framework/views -RUN mkdir -p /lumen/storage/framework/cache +RUN mkdir -p storage \ + storage/framework/sessions \ + storage/framework/views \ + storage/framework/cache RUN chmod -R 777 /lumen diff --git a/frameworks/PHP/lumen/lumen.dockerfile b/frameworks/PHP/lumen/lumen.dockerfile index 1b5f8a76e62..9d11da427af 100644 --- a/frameworks/PHP/lumen/lumen.dockerfile +++ b/frameworks/PHP/lumen/lumen.dockerfile @@ -1,4 +1,4 @@ -FROM ubuntu:22.04 +FROM ubuntu:24.04 ARG DEBIAN_FRONTEND=noninteractive @@ -13,17 +13,18 @@ COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer COPY deploy/conf/* /etc/php/8.3/fpm/ -ADD ./ /lumen WORKDIR /lumen +COPY --link . . + RUN if [ $(nproc) = 2 ]; then sed -i "s|pm.max_children = 1024|pm.max_children = 512|g" /etc/php/8.3/fpm/php-fpm.conf ; fi; RUN composer install --optimize-autoloader --classmap-authoritative --no-dev --quiet -RUN mkdir -p /lumen/storage -RUN mkdir -p /lumen/storage/framework/sessions -RUN mkdir -p /lumen/storage/framework/views -RUN mkdir -p /lumen/storage/framework/cache +RUN mkdir -p storage \ + storage/framework/sessions \ + storage/framework/views \ + storage/framework/cache RUN chmod -R 777 /lumen From a74a2d21018caf2683fef8133fc69d4c97e94b16 Mon Sep 17 00:00:00 2001 From: Joan Miquel Date: Thu, 8 Aug 2024 22:06:59 +0200 Subject: [PATCH 063/204] [ci skip] Silverlining change display name in prefork (#9195) --- frameworks/Go/silverlining/benchmark_config.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frameworks/Go/silverlining/benchmark_config.json b/frameworks/Go/silverlining/benchmark_config.json index 368481b04cf..bd8544f9111 100644 --- a/frameworks/Go/silverlining/benchmark_config.json +++ b/frameworks/Go/silverlining/benchmark_config.json @@ -35,7 +35,7 @@ "webserver": "None", "os": "Linux", "database_os": "Linux", - "display_name": "silverlining", + "display_name": "silverlining [prefork]", "notes": "", "versus": "go" } From 1c0d617f696575caf080d12ed3014cc04b70d58e Mon Sep 17 00:00:00 2001 From: Rasmus Porsager Date: Thu, 8 Aug 2024 22:07:20 +0200 Subject: [PATCH 064/204] Send less with uWebSockets.js (#9194) * Send less * Fix method name * And on the right object --- frameworks/JavaScript/uwebsockets.js/src/server.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/frameworks/JavaScript/uwebsockets.js/src/server.js b/frameworks/JavaScript/uwebsockets.js/src/server.js index 1db7d391f2a..0305347a2cf 100644 --- a/frameworks/JavaScript/uwebsockets.js/src/server.js +++ b/frameworks/JavaScript/uwebsockets.js/src/server.js @@ -16,8 +16,10 @@ if (DATABASE) db = await import(`./database/${DATABASE}.js`); const webserver = uWebSockets.App(); +uWebSockets._cfg('silent'); + webserver.get("/plaintext", new uWebSockets.DeclarativeResponse() - .writeHeader("Server", "uWebSockets.js") + .writeHeader("Server", "uWS") .writeHeader("Content-Type", "text/plain") .end("Hello, World!") ); @@ -90,7 +92,7 @@ if (db) { handleError(error, response); } }); - + const extra = { id: 0, message: "Additional fortune added at request time." }; webserver.get("/fortunes", async (response) => { From 5e66b478e6f10208e10eaead87632d8eb1913f21 Mon Sep 17 00:00:00 2001 From: Redkale Date: Fri, 9 Aug 2024 04:07:45 +0800 Subject: [PATCH 065/204] Update Redkale 2.9.0-SNAPSHOT (#9193) * Update Redkale 2.9.0-SNAPSHOT * Update Redkale 2.9.0-SNAPSHOT --- frameworks/Java/redkale/pom-jdbc.xml | 5 +- frameworks/Java/redkale/pom-vertx.xml | 5 +- frameworks/Java/redkale/pom.xml | 5 +- .../java/org/redkalex/benchmark/Message.java | 81 +++++++++---------- 4 files changed, 49 insertions(+), 47 deletions(-) diff --git a/frameworks/Java/redkale/pom-jdbc.xml b/frameworks/Java/redkale/pom-jdbc.xml index 43ce0fa4e0f..93df4fb9464 100644 --- a/frameworks/Java/redkale/pom-jdbc.xml +++ b/frameworks/Java/redkale/pom-jdbc.xml @@ -7,7 +7,8 @@ org.redkale.boot.Application - 2.8.0-SNAPSHOT + 2.9.0-SNAPSHOT + 1.3.0-SNAPSHOT 42.6.0 UTF-8 18 @@ -85,7 +86,7 @@ org.redkale.maven.plugins redkale-maven-plugin - 1.2.0-SNAPSHOT + ${redkale-maven.version} --no-fallback diff --git a/frameworks/Java/redkale/pom-vertx.xml b/frameworks/Java/redkale/pom-vertx.xml index 9879cff1237..fc371f67798 100644 --- a/frameworks/Java/redkale/pom-vertx.xml +++ b/frameworks/Java/redkale/pom-vertx.xml @@ -7,7 +7,8 @@ org.redkale.boot.Application - 2.8.0-SNAPSHOT + 2.9.0-SNAPSHOT + 1.3.0-SNAPSHOT 4.5.0 2.1 UTF-8 @@ -92,7 +93,7 @@ org.redkale.maven.plugins redkale-maven-plugin - 1.2.0-SNAPSHOT + ${redkale-maven.version} --no-fallback diff --git a/frameworks/Java/redkale/pom.xml b/frameworks/Java/redkale/pom.xml index 8e6fa747ac0..78ffcbdd93b 100644 --- a/frameworks/Java/redkale/pom.xml +++ b/frameworks/Java/redkale/pom.xml @@ -7,7 +7,8 @@ org.redkale.boot.Application - 2.8.0-SNAPSHOT + 2.9.0-SNAPSHOT + 1.3.0-SNAPSHOT UTF-8 11 11 @@ -74,7 +75,7 @@ org.redkale.maven.plugins redkale-maven-plugin - 1.2.0-SNAPSHOT + ${redkale-maven.version} --no-fallback diff --git a/frameworks/Java/redkale/src/main/java/org/redkalex/benchmark/Message.java b/frameworks/Java/redkale/src/main/java/org/redkalex/benchmark/Message.java index 73cbe2c2afd..00c529e9eee 100644 --- a/frameworks/Java/redkale/src/main/java/org/redkalex/benchmark/Message.java +++ b/frameworks/Java/redkale/src/main/java/org/redkalex/benchmark/Message.java @@ -1,41 +1,40 @@ -/* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. - */ -package org.redkalex.benchmark; - -import org.redkale.annotation.Bean; -import org.redkale.convert.ConvertSmallString; -import org.redkale.convert.json.JsonConvert; - -/** - * - * @author zhangjx - */ -@Bean -public final class Message { - - @ConvertSmallString - private String message; - - public Message() { - } - - public Message(String message) { - this.message = message; - } - - public String getMessage() { - return message; - } - - public void setMessage(String message) { - this.message = message; - } - - @Override - public String toString() { - return JsonConvert.root().convertTo(this); - } -} +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.redkalex.benchmark; + +import org.redkale.annotation.Serial; +import org.redkale.convert.ConvertSmallString; +import org.redkale.convert.json.JsonConvert; + +/** + * + * @author zhangjx + */ +@Serial +public final class Message { + + @ConvertSmallString + private String message; + + public Message() {} + + public Message(String message) { + this.message = message; + } + + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } + + @Override + public String toString() { + return JsonConvert.root().convertTo(this); + } +} From 48075478254408c7a210698b2f0953dd79a81253 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 9 Aug 2024 18:17:14 +0000 Subject: [PATCH 066/204] Bump aiohttp from 3.9.4 to 3.10.2 in /frameworks/Python/api_hour Bumps [aiohttp](https://github.com/aio-libs/aiohttp) from 3.9.4 to 3.10.2. - [Release notes](https://github.com/aio-libs/aiohttp/releases) - [Changelog](https://github.com/aio-libs/aiohttp/blob/master/CHANGES.rst) - [Commits](https://github.com/aio-libs/aiohttp/compare/v3.9.4...v3.10.2) --- updated-dependencies: - dependency-name: aiohttp dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- frameworks/Python/api_hour/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frameworks/Python/api_hour/requirements.txt b/frameworks/Python/api_hour/requirements.txt index 81b923f4005..19dcab407ab 100644 --- a/frameworks/Python/api_hour/requirements.txt +++ b/frameworks/Python/api_hour/requirements.txt @@ -1,4 +1,4 @@ -aiohttp==3.9.4 +aiohttp==3.10.2 -e git+https://github.com/Eyepea/aiohttp_jinja2.git@c9675e5c1e1ee7741b30aea8d8fbffcde016c7a0#egg=aiohttp_jinja2-master aiopg==0.7.0 -e git+https://github.com/Eyepea/API-Hour.git@577abbdcbb8cc2810dad46e260b338b15db4d0e3#egg=api_hour-master From e05436e96c606be703cd75e52b8c5c192e3f0d7b Mon Sep 17 00:00:00 2001 From: Petrik de Heus Date: Tue, 13 Aug 2024 21:43:37 +0200 Subject: [PATCH 067/204] [rails] Upgrade to Rails 7.2 (#9209) Update to latest release. - Remove YJIT initializer as YJIT is enabled by Rails by default. - Updated config with bin/rails app:update --- frameworks/Ruby/rails/.ruby-version | 2 +- frameworks/Ruby/rails/Gemfile | 2 +- frameworks/Ruby/rails/Gemfile.lock | 170 +++++++++--------- frameworks/Ruby/rails/config/application.rb | 13 +- .../rails/config/environments/development.rb | 19 +- .../rails/config/environments/production.rb | 52 +++--- .../Ruby/rails/config/environments/test.rb | 24 ++- .../rails/config/initializers/enable_yjit.rb | 11 -- frameworks/Ruby/rails/config/puma.rb | 67 +++---- 9 files changed, 167 insertions(+), 193 deletions(-) delete mode 100644 frameworks/Ruby/rails/config/initializers/enable_yjit.rb diff --git a/frameworks/Ruby/rails/.ruby-version b/frameworks/Ruby/rails/.ruby-version index fd2a01863fd..15a27998172 100644 --- a/frameworks/Ruby/rails/.ruby-version +++ b/frameworks/Ruby/rails/.ruby-version @@ -1 +1 @@ -3.1.0 +3.3.0 diff --git a/frameworks/Ruby/rails/Gemfile b/frameworks/Ruby/rails/Gemfile index 39eb973e700..8039ed09fd9 100644 --- a/frameworks/Ruby/rails/Gemfile +++ b/frameworks/Ruby/rails/Gemfile @@ -3,7 +3,7 @@ source 'https://rubygems.org' gem 'oj', '~> 3.16' gem 'pg', '~> 1.5', group: :postgresql gem 'puma', '~> 6.4' -gem 'rails', '~> 7.1.3' +gem 'rails', '~> 7.2.0' gem 'redis', '~> 5.0' gem 'trilogy', '~> 2.8.1', group: :mysql gem 'tzinfo-data' diff --git a/frameworks/Ruby/rails/Gemfile.lock b/frameworks/Ruby/rails/Gemfile.lock index 5c25771e659..dfa97091616 100644 --- a/frameworks/Ruby/rails/Gemfile.lock +++ b/frameworks/Ruby/rails/Gemfile.lock @@ -1,97 +1,94 @@ GEM remote: https://rubygems.org/ specs: - actioncable (7.1.3.4) - actionpack (= 7.1.3.4) - activesupport (= 7.1.3.4) + actioncable (7.2.0) + actionpack (= 7.2.0) + activesupport (= 7.2.0) nio4r (~> 2.0) websocket-driver (>= 0.6.1) zeitwerk (~> 2.6) - actionmailbox (7.1.3.4) - actionpack (= 7.1.3.4) - activejob (= 7.1.3.4) - activerecord (= 7.1.3.4) - activestorage (= 7.1.3.4) - activesupport (= 7.1.3.4) - mail (>= 2.7.1) - net-imap - net-pop - net-smtp - actionmailer (7.1.3.4) - actionpack (= 7.1.3.4) - actionview (= 7.1.3.4) - activejob (= 7.1.3.4) - activesupport (= 7.1.3.4) - mail (~> 2.5, >= 2.5.4) - net-imap - net-pop - net-smtp + actionmailbox (7.2.0) + actionpack (= 7.2.0) + activejob (= 7.2.0) + activerecord (= 7.2.0) + activestorage (= 7.2.0) + activesupport (= 7.2.0) + mail (>= 2.8.0) + actionmailer (7.2.0) + actionpack (= 7.2.0) + actionview (= 7.2.0) + activejob (= 7.2.0) + activesupport (= 7.2.0) + mail (>= 2.8.0) rails-dom-testing (~> 2.2) - actionpack (7.1.3.4) - actionview (= 7.1.3.4) - activesupport (= 7.1.3.4) + actionpack (7.2.0) + actionview (= 7.2.0) + activesupport (= 7.2.0) nokogiri (>= 1.8.5) racc - rack (>= 2.2.4) + rack (>= 2.2.4, < 3.2) rack-session (>= 1.0.1) rack-test (>= 0.6.3) rails-dom-testing (~> 2.2) rails-html-sanitizer (~> 1.6) - actiontext (7.1.3.4) - actionpack (= 7.1.3.4) - activerecord (= 7.1.3.4) - activestorage (= 7.1.3.4) - activesupport (= 7.1.3.4) + useragent (~> 0.16) + actiontext (7.2.0) + actionpack (= 7.2.0) + activerecord (= 7.2.0) + activestorage (= 7.2.0) + activesupport (= 7.2.0) globalid (>= 0.6.0) nokogiri (>= 1.8.5) - actionview (7.1.3.4) - activesupport (= 7.1.3.4) + actionview (7.2.0) + activesupport (= 7.2.0) builder (~> 3.1) erubi (~> 1.11) rails-dom-testing (~> 2.2) rails-html-sanitizer (~> 1.6) - activejob (7.1.3.4) - activesupport (= 7.1.3.4) + activejob (7.2.0) + activesupport (= 7.2.0) globalid (>= 0.3.6) - activemodel (7.1.3.4) - activesupport (= 7.1.3.4) - activerecord (7.1.3.4) - activemodel (= 7.1.3.4) - activesupport (= 7.1.3.4) + activemodel (7.2.0) + activesupport (= 7.2.0) + activerecord (7.2.0) + activemodel (= 7.2.0) + activesupport (= 7.2.0) timeout (>= 0.4.0) - activestorage (7.1.3.4) - actionpack (= 7.1.3.4) - activejob (= 7.1.3.4) - activerecord (= 7.1.3.4) - activesupport (= 7.1.3.4) + activestorage (7.2.0) + actionpack (= 7.2.0) + activejob (= 7.2.0) + activerecord (= 7.2.0) + activesupport (= 7.2.0) marcel (~> 1.0) - activesupport (7.1.3.4) + activesupport (7.2.0) base64 bigdecimal - concurrent-ruby (~> 1.0, >= 1.0.2) + concurrent-ruby (~> 1.0, >= 1.3.1) connection_pool (>= 2.2.5) drb i18n (>= 1.6, < 2) + logger (>= 1.4.2) minitest (>= 5.1) - mutex_m - tzinfo (~> 2.0) + securerandom (>= 0.3) + tzinfo (~> 2.0, >= 2.0.5) base64 (0.2.0) bigdecimal (3.1.8) - builder (3.2.4) - concurrent-ruby (1.3.1) + builder (3.3.0) + concurrent-ruby (1.3.4) connection_pool (2.4.1) crass (1.0.6) date (3.3.4) drb (2.2.1) - erubi (1.12.0) + erubi (1.13.0) globalid (1.2.1) activesupport (>= 6.1) i18n (1.14.5) concurrent-ruby (~> 1.0) io-console (0.7.2) - irb (1.13.1) + irb (1.14.0) rdoc (>= 4.0.0) reline (>= 0.4.2) + logger (1.6.0) loofah (2.22.0) crass (~> 1.0.2) nokogiri (>= 1.12.0) @@ -103,9 +100,8 @@ GEM marcel (1.0.4) mini_mime (1.1.5) mini_portile2 (2.8.7) - minitest (5.23.1) - mutex_m (0.2.0) - net-imap (0.4.11) + minitest (5.24.1) + net-imap (0.4.14) date net-protocol net-pop (0.1.2) @@ -115,22 +111,24 @@ GEM net-smtp (0.5.0) net-protocol nio4r (2.7.3) - nokogiri (1.16.5) + nokogiri (1.16.7) mini_portile2 (~> 2.8.2) racc (~> 1.4) - nokogiri (1.16.5-arm64-darwin) + nokogiri (1.16.7-arm64-darwin) racc (~> 1.4) - nokogiri (1.16.5-x86_64-linux) + nokogiri (1.16.7-x86_64-linux) racc (~> 1.4) - oj (3.16.3) + oj (3.16.5) bigdecimal (>= 3.0) - pg (1.5.6) + ostruct (>= 0.2) + ostruct (0.6.0) + pg (1.5.7) psych (5.1.2) stringio puma (6.4.2) nio4r (~> 2.0) - racc (1.8.0) - rack (3.0.11) + racc (1.8.1) + rack (3.1.7) rack-session (2.0.0) rack (>= 3.0.0) rack-test (2.1.0) @@ -138,20 +136,20 @@ GEM rackup (2.1.0) rack (>= 3) webrick (~> 1.8) - rails (7.1.3.4) - actioncable (= 7.1.3.4) - actionmailbox (= 7.1.3.4) - actionmailer (= 7.1.3.4) - actionpack (= 7.1.3.4) - actiontext (= 7.1.3.4) - actionview (= 7.1.3.4) - activejob (= 7.1.3.4) - activemodel (= 7.1.3.4) - activerecord (= 7.1.3.4) - activestorage (= 7.1.3.4) - activesupport (= 7.1.3.4) + rails (7.2.0) + actioncable (= 7.2.0) + actionmailbox (= 7.2.0) + actionmailer (= 7.2.0) + actionpack (= 7.2.0) + actiontext (= 7.2.0) + actionview (= 7.2.0) + activejob (= 7.2.0) + activemodel (= 7.2.0) + activerecord (= 7.2.0) + activestorage (= 7.2.0) + activesupport (= 7.2.0) bundler (>= 1.15.0) - railties (= 7.1.3.4) + railties (= 7.2.0) rails-dom-testing (2.2.0) activesupport (>= 5.0.0) minitest @@ -159,24 +157,25 @@ GEM rails-html-sanitizer (1.6.0) loofah (~> 2.21) nokogiri (~> 1.14) - railties (7.1.3.4) - actionpack (= 7.1.3.4) - activesupport (= 7.1.3.4) - irb + railties (7.2.0) + actionpack (= 7.2.0) + activesupport (= 7.2.0) + irb (~> 1.13) rackup (>= 1.0.0) rake (>= 12.2) thor (~> 1.0, >= 1.2.2) zeitwerk (~> 2.6) rake (13.2.1) - rdoc (6.6.3.1) + rdoc (6.7.0) psych (>= 4.0.0) redis (5.2.0) redis-client (>= 0.22.0) redis-client (0.22.2) connection_pool - reline (0.5.7) + reline (0.5.9) io-console (~> 0.5) - stringio (3.1.0) + securerandom (0.3.1) + stringio (3.1.1) thor (1.3.1) timeout (0.4.1) trilogy (2.8.1) @@ -184,11 +183,12 @@ GEM concurrent-ruby (~> 1.0) tzinfo-data (1.2024.1) tzinfo (>= 1.0.0) + useragent (0.16.10) webrick (1.8.1) websocket-driver (0.7.6) websocket-extensions (>= 0.1.0) websocket-extensions (0.1.5) - zeitwerk (2.6.14) + zeitwerk (2.6.17) PLATFORMS arm64-darwin-20 @@ -199,7 +199,7 @@ DEPENDENCIES oj (~> 3.16) pg (~> 1.5) puma (~> 6.4) - rails (~> 7.1.3) + rails (~> 7.2.0) redis (~> 5.0) trilogy (~> 2.8.1) tzinfo-data diff --git a/frameworks/Ruby/rails/config/application.rb b/frameworks/Ruby/rails/config/application.rb index 2cca7e95baa..7e3e1d4af56 100644 --- a/frameworks/Ruby/rails/config/application.rb +++ b/frameworks/Ruby/rails/config/application.rb @@ -8,9 +8,10 @@ # require "active_storage/engine" require "action_controller/railtie" # require "action_mailer/railtie" +# require "action_mailbox/engine" +# require "action_text/engine" require "action_view/railtie" # require "action_cable/engine" -# require "sprockets/railtie" # require "rails/test_unit/railtie" # Require the gems listed in Gemfile, including any gems @@ -20,12 +21,12 @@ module Hello class Application < Rails::Application # Initialize configuration defaults for originally generated Rails version. - config.load_defaults 7.1 + config.load_defaults 7.2 - # Settings in config/environments/* take precedence over those specified here. - # Application configuration can go into files in config/initializers - # -- all .rb files in that directory are automatically loaded after loading - # the framework and any gems in your application. + # Please, add to the `ignore` list any other `lib` subdirectories that do + # not contain `.rb` files, or that should not be reloaded or eager loaded. + # Common ones are `templates`, `generators`, or `middleware`, for example. + config.autoload_lib(ignore: %w[assets tasks]) config.action_dispatch.default_headers.merge!('Server' => 'WebServer') diff --git a/frameworks/Ruby/rails/config/environments/development.rb b/frameworks/Ruby/rails/config/environments/development.rb index 8620b53db5a..6a2306dbabc 100644 --- a/frameworks/Ruby/rails/config/environments/development.rb +++ b/frameworks/Ruby/rails/config/environments/development.rb @@ -6,7 +6,7 @@ # In the development environment your application's code is reloaded any time # it changes. This slows down response time but is perfect for development # since you don't have to restart the web server when you make code changes. - config.cache_classes = false + config.enable_reloading = true # Do not eager load code on boot. config.eager_load = false @@ -14,7 +14,7 @@ # Show full error reports. config.consider_all_requests_local = true - # Enable server timing + # Enable server timing. config.server_timing = true # Enable/disable caching. By default caching is disabled. @@ -24,9 +24,7 @@ config.action_controller.enable_fragment_cache_logging = true config.cache_store = :memory_store - config.public_file_server.headers = { - "Cache-Control" => "public, max-age=#{2.days.to_i}" - } + config.public_file_server.headers = { "Cache-Control" => "public, max-age=#{2.days.to_i}" } else config.action_controller.perform_caching = false @@ -48,16 +46,15 @@ # Highlight code that triggered database queries in logs. config.active_record.verbose_query_logs = true - # Raises error for missing translations. # config.i18n.raise_on_missing_translations = true # Annotate rendered view with file names. - # config.action_view.annotate_rendered_view_with_filenames = true - - # Uncomment if you wish to allow Action Cable access from any origin. - # config.action_cable.disable_request_forgery_protection = true + config.action_view.annotate_rendered_view_with_filenames = true - # Raise error when a before_action's only/except options reference missing actions + # Raise error when a before_action's only/except options reference missing actions. config.action_controller.raise_on_missing_callback_actions = true + + # Apply autocorrection by RuboCop to files generated by `bin/rails generate`. + # config.generators.apply_rubocop_autocorrect_after_generate! end diff --git a/frameworks/Ruby/rails/config/environments/production.rb b/frameworks/Ruby/rails/config/environments/production.rb index 3ad22143e26..f9de0f173d6 100644 --- a/frameworks/Ruby/rails/config/environments/production.rb +++ b/frameworks/Ruby/rails/config/environments/production.rb @@ -4,7 +4,7 @@ # Settings specified here will take precedence over those in config/application.rb. # Code is not reloaded between requests. - config.cache_classes = true + config.enable_reloading = false # Eager load code on boot. This eager loads most of Rails and # your application in memory, allowing both threaded web servers @@ -13,16 +13,15 @@ config.eager_load = true # Full error reports are disabled and caching is turned on. - config.consider_all_requests_local = false + config.consider_all_requests_local = false config.action_controller.perform_caching = true - # Ensures that a master key has been made available in either ENV["RAILS_MASTER_KEY"] - # or in config/master.key. This key is used to decrypt credentials (and other encrypted files). + # Ensures that a master key has been made available in ENV["RAILS_MASTER_KEY"], config/master.key, or an environment + # key such as config/credentials/production.key. This key is used to decrypt credentials (and other encrypted files). # config.require_master_key = true - # Disable serving static files from the `/public` folder by default since - # Apache or NGINX already handles this. - config.public_file_server.enabled = ENV["RAILS_SERVE_STATIC_FILES"].present? + # Disable serving static files from `public/`, relying on NGINX/Apache to do so instead. + # config.public_file_server.enabled = false # Enable serving of images, stylesheets, and JavaScripts from an asset server. # config.asset_host = "http://assets.example.com" @@ -31,16 +30,24 @@ # config.action_dispatch.x_sendfile_header = "X-Sendfile" # for Apache # config.action_dispatch.x_sendfile_header = "X-Accel-Redirect" # for NGINX + # Assume all access to the app is happening through a SSL-terminating reverse proxy. + # Can be used together with config.force_ssl for Strict-Transport-Security and secure cookies. + # config.assume_ssl = true + # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies. # config.force_ssl = true - # Include generic and useful information about system operation, but avoid logging too much - # information to avoid inadvertent exposure of personally identifiable information (PII). - config.log_level = :info + # Skip http-to-https redirect for the default health check endpoint. + # config.ssl_options = { redirect: { exclude: ->(request) { request.path == "/up" } } } # Prepend all log lines with the following tags. config.log_tags = [ :request_id ] + # "info" includes generic and useful information about system operation, but avoids logging too much + # information to avoid inadvertent exposure of personally identifiable information (PII). If you + # want to log everything, set the level to "debug". + config.log_level = ENV.fetch("RAILS_LOG_LEVEL", "info") + # Use a different cache store in production. config.cache_store = :redis_cache_store, { url: ENV['REDIS_URL'], @@ -54,10 +61,6 @@ } } - # Use a real queuing backend for Active Job (and separate queues per environment). - # config.active_job.queue_adapter = :resque - # config.active_job.queue_name_prefix = "hello_production" - # Enable locale fallbacks for I18n (makes lookups for any locale fall back to # the I18n.default_locale when a translation cannot be found). config.i18n.fallbacks = true @@ -65,19 +68,14 @@ # Don't log any deprecations. config.active_support.report_deprecations = false - # Use default logging formatter so that PID and timestamp are not suppressed. - config.log_formatter = ::Logger::Formatter.new - - # Use a different logger for distributed setups. - # require "syslog/logger" - # config.logger = ActiveSupport::TaggedLogging.new(Syslog::Logger.new "app-name") - - if ENV["RAILS_LOG_TO_STDOUT"].present? - logger = ActiveSupport::Logger.new(STDOUT) - logger.formatter = config.log_formatter - config.logger = ActiveSupport::TaggedLogging.new(logger) - end - # Do not dump schema after migrations. config.active_record.dump_schema_after_migration = false + + # Enable DNS rebinding protection and other `Host` header attacks. + # config.hosts = [ + # "example.com", # Allow requests from example.com + # /.*\.example\.com/ # Allow requests from subdomains like `www.example.com` + # ] + # Skip DNS rebinding protection for the default health check endpoint. + # config.host_authorization = { exclude: ->(request) { request.path == "/up" } } end diff --git a/frameworks/Ruby/rails/config/environments/test.rb b/frameworks/Ruby/rails/config/environments/test.rb index bfcd30081b1..999db7091ef 100644 --- a/frameworks/Ruby/rails/config/environments/test.rb +++ b/frameworks/Ruby/rails/config/environments/test.rb @@ -8,27 +8,25 @@ Rails.application.configure do # Settings specified here will take precedence over those in config/application.rb. - # Turn false under Spring and add config.action_view.cache_template_loading = true. - config.cache_classes = true + # While tests run files are not watched, reloading is not necessary. + config.enable_reloading = false - # Eager loading loads your whole application. When running a single test locally, - # this probably isn't necessary. It's a good idea to do in a continuous integration - # system, or in some way before deploying your code. + # Eager loading loads your entire application. When running a single test locally, + # this is usually not necessary, and can slow down your test suite. However, it's + # recommended that you enable it in continuous integration systems to ensure eager + # loading is working properly before deploying your code. config.eager_load = ENV["CI"].present? # Configure public file server for tests with Cache-Control for performance. - config.public_file_server.enabled = true - config.public_file_server.headers = { - "Cache-Control" => "public, max-age=#{1.hour.to_i}" - } + config.public_file_server.headers = { "Cache-Control" => "public, max-age=#{1.hour.to_i}" } # Show full error reports and disable caching. - config.consider_all_requests_local = true + config.consider_all_requests_local = true config.action_controller.perform_caching = false config.cache_store = :null_store - # Raise exceptions instead of rendering exception templates. - config.action_dispatch.show_exceptions = false + # Render exception templates for rescuable exceptions and raise for other exceptions. + config.action_dispatch.show_exceptions = :rescuable # Disable request forgery protection in test environment. config.action_controller.allow_forgery_protection = false @@ -48,6 +46,6 @@ # Annotate rendered view with file names. # config.action_view.annotate_rendered_view_with_filenames = true - # Raise error when a before_action's only/except options reference missing actions + # Raise error when a before_action's only/except options reference missing actions. config.action_controller.raise_on_missing_callback_actions = true end diff --git a/frameworks/Ruby/rails/config/initializers/enable_yjit.rb b/frameworks/Ruby/rails/config/initializers/enable_yjit.rb deleted file mode 100644 index 963858ab4c6..00000000000 --- a/frameworks/Ruby/rails/config/initializers/enable_yjit.rb +++ /dev/null @@ -1,11 +0,0 @@ -# Automatically enable YJIT as of Ruby 3.3, as it bring very -# sizeable performance improvements. - -# If you are deploying to a memory constrained environment -# you may want to delete this file, but otherwise it's free -# performance. -if defined? RubyVM::YJIT.enable - Rails.application.config.after_initialize do - RubyVM::YJIT.enable - end -end diff --git a/frameworks/Ruby/rails/config/puma.rb b/frameworks/Ruby/rails/config/puma.rb index 3089f8334a2..b513db258e6 100644 --- a/frameworks/Ruby/rails/config/puma.rb +++ b/frameworks/Ruby/rails/config/puma.rb @@ -1,49 +1,40 @@ -require_relative 'auto_tune' +# This configuration file will be evaluated by Puma. The top-level methods that +# are invoked here are part of Puma's configuration DSL. For more information +# about methods provided by the DSL, see https://puma.io/puma/Puma/DSL.html. -# FWBM only... use the puma_auto_tune gem in production! -tuned_num_workers, tuned_num_threads = auto_tune +require_relative 'auto_tune' -# Puma can serve each request in a thread from an internal thread pool. -# The `threads` method setting takes two numbers: a minimum and maximum. -# Any libraries that use thread pools should be configured to match -# the maximum value specified for Puma. Default is set to 5 threads for minimum -# and maximum; this matches the default thread size of Active Record. +# Puma starts a configurable number of processes (workers) and each process +# serves each request in a thread from an internal thread pool. # -max_threads_count = ENV.fetch("RAILS_MAX_THREADS") { 3 } -min_threads_count = ENV.fetch("RAILS_MIN_THREADS") { max_threads_count } -threads min_threads_count, max_threads_count - -# Specifies the `worker_timeout` threshold that Puma will use to wait before -# terminating a worker in development environments. +# The ideal number of threads per worker depends both on how much time the +# application spends waiting for IO operations and on how much you wish to +# to prioritize throughput over latency. # -worker_timeout 3600 if ENV.fetch("RAILS_ENV", "development") == "development" - -# Specifies the `port` that Puma will listen on to receive requests; default is 3000. +# As a rule of thumb, increasing the number of threads will increase how much +# traffic a given process can handle (throughput), but due to CRuby's +# Global VM Lock (GVL) it has diminishing returns and will degrade the +# response time (latency) of the application. # -port ENV.fetch("PORT") { 3000 } - -# Specifies the `environment` that Puma will run in. +# The default is set to 3 threads as it's deemed a decent compromise between +# throughput and latency for the average Rails application. # -environment ENV.fetch("RAILS_ENV") { "development" } +# Any libraries that use a connection pool or another resource pool should +# be configured to provide at least as many connections as the number of +# threads. This includes Active Record's `pool` parameter in `database.yml`. +threads_count = ENV.fetch("RAILS_MAX_THREADS", 3) +threads threads_count, threads_count -# Specifies the `pidfile` that Puma will use. -pidfile ENV.fetch("PIDFILE") { "tmp/pids/server.pid" } +worker_timeout 3600 if ENV.fetch("RAILS_ENV", "development") == "development" -# Specifies the number of `workers` to boot in clustered mode. -# Workers are forked web server processes. If using threads and workers together -# the concurrency of the application would be max `threads` * `workers`. -# Workers do not work on JRuby or Windows (both of which do not support -# processes). -# -# workers ENV.fetch("WEB_CONCURRENCY") { 2 } -workers tuned_num_workers +# Specifies the `port` that Puma will listen on to receive requests; default is 3000. +port ENV.fetch("PORT", 3000) -# Use the `preload_app!` method when specifying a `workers` number. -# This directive tells Puma to first boot the application and load code -# before forking the application. This takes advantage of Copy On Write -# process behavior so workers use less memory. -# -preload_app! +tuned_num_workers, tuned_num_threads = auto_tune +workers tuned_num_workers -# Allow puma to be restarted by `rails restart` command. +# Allow puma to be restarted by `bin/rails restart` command. plugin :tmp_restart + +# Only use a pidfile when requested +pidfile ENV["PIDFILE"] if ENV["PIDFILE"] From a77b6eb051ce3fe60104161821b348312e7c3806 Mon Sep 17 00:00:00 2001 From: Julien Viet Date: Tue, 13 Aug 2024 21:43:46 +0200 Subject: [PATCH 068/204] Revert for now native epoll on linux instead of io-uring (#9208) --- frameworks/Java/vertx/pom.xml | 3 --- 1 file changed, 3 deletions(-) diff --git a/frameworks/Java/vertx/pom.xml b/frameworks/Java/vertx/pom.xml index 06199d308db..4230d89326b 100644 --- a/frameworks/Java/vertx/pom.xml +++ b/frameworks/Java/vertx/pom.xml @@ -148,9 +148,6 @@ Linux false - - unix - From 919e13b01eea0470f48f04fc766aa6d724d6ea52 Mon Sep 17 00:00:00 2001 From: Nikolay Kim Date: Wed, 14 Aug 2024 00:43:56 +0500 Subject: [PATCH 069/204] ntex: update version, try different allocator (#9206) --- frameworks/Rust/ntex/Cargo.toml | 2 +- frameworks/Rust/ntex/src/db.rs | 59 ++++++++++++++-------------- frameworks/Rust/ntex/src/main.rs | 3 +- frameworks/Rust/ntex/src/main_db.rs | 4 +- frameworks/Rust/ntex/src/main_plt.rs | 1 + 5 files changed, 35 insertions(+), 34 deletions(-) diff --git a/frameworks/Rust/ntex/Cargo.toml b/frameworks/Rust/ntex/Cargo.toml index 6699c6c0f1d..92c0da890ac 100755 --- a/frameworks/Rust/ntex/Cargo.toml +++ b/frameworks/Rust/ntex/Cargo.toml @@ -37,7 +37,7 @@ tokio = ["ntex/tokio"] async-std = ["ntex/async-std"] [dependencies] -ntex = "=2.0.3" +ntex = "=2.1.0" ntex-bytes = { version = "0.1.21", features=["simd"] } mimalloc = { version = "0.1.25", default-features = false } snmalloc-rs = { version = "0.3.3", features = ["native-cpu"] } diff --git a/frameworks/Rust/ntex/src/db.rs b/frameworks/Rust/ntex/src/db.rs index 5bceed5b73e..b3adc6e70bf 100644 --- a/frameworks/Rust/ntex/src/db.rs +++ b/frameworks/Rust/ntex/src/db.rs @@ -1,11 +1,11 @@ -use std::{cell::RefCell, fmt::Write as FmtWrite}; +#![allow(clippy::uninit_vec)] +use std::{borrow::Cow, cell::RefCell, fmt::Write as FmtWrite}; -use futures::stream::{futures_unordered::FuturesUnordered, StreamExt}; use nanorand::{Rng, WyRand}; use ntex::util::{BufMut, Bytes, BytesMut}; use smallvec::SmallVec; use tokio_postgres::types::ToSql; -use tokio_postgres::{connect, Client, Row, Statement}; +use tokio_postgres::{connect, Client, Statement}; use yarte::{ywrite_html, Serialize}; use super::utils; @@ -17,9 +17,9 @@ pub struct World { } #[derive(Serialize, Debug)] -pub struct Fortune<'a> { +pub struct Fortune { pub id: i32, - pub message: &'a str, + pub message: Cow<'static, str>, } /// Postgres interface @@ -60,10 +60,7 @@ impl PgConnection { q.push(')'); updates.push(cl.prepare(&q).await.unwrap()); } - let world = cl - .prepare("SELECT id, randomnumber FROM world WHERE id=$1") - .await - .unwrap(); + let world = cl.prepare("SELECT * FROM world WHERE id=$1").await.unwrap(); PgConnection { cl, @@ -83,7 +80,7 @@ impl PgConnection { let row = self.cl.query_one(&self.world, &[&random_id]).await.unwrap(); let mut body = self.buf.borrow_mut(); - utils::reserve(&mut body, 256); + utils::reserve(&mut body, 8 * 1024); World { id: row.get(0), randomnumber: row.get(1), @@ -92,20 +89,17 @@ impl PgConnection { body.split().freeze() } - async fn get_one_world(&self, id: i32) -> Row { - self.cl.query_one(&self.world, &[&id]).await.unwrap() - } - pub async fn get_worlds(&self, num: usize) -> Bytes { let mut rng = self.rng.clone(); - let mut queries = FuturesUnordered::new(); + let mut queries = SmallVec::<[_; 32]>::new(); (0..num).for_each(|_| { let w_id = (rng.generate::() % 10_000 + 1) as i32; - queries.push(self.get_one_world(w_id)) + queries.push(self.cl.query_one(&self.world, &[&w_id])); }); let mut worlds = SmallVec::<[_; 32]>::new(); - while let Some(row) = queries.next().await { + for fut in queries { + let row = fut.await.unwrap(); worlds.push(World { id: row.get(0), randomnumber: row.get(1), @@ -126,14 +120,15 @@ impl PgConnection { pub async fn update(&self, num: usize) -> Bytes { let mut rng = self.rng.clone(); - let mut queries = FuturesUnordered::new(); + let mut queries = SmallVec::<[_; 32]>::new(); (0..num).for_each(|_| { let w_id = (rng.generate::() % 10_000 + 1) as i32; - queries.push(self.get_one_world(w_id)) + queries.push(self.cl.query_one(&self.world, &[&w_id])); }); let mut worlds = SmallVec::<[_; 32]>::new(); - while let Some(row) = queries.next().await { + for fut in queries.into_iter() { + let row = fut.await.unwrap(); worlds.push(World { id: row.get(0), randomnumber: (rng.generate::() % 10_000 + 1) as i32, @@ -163,18 +158,22 @@ impl PgConnection { } pub async fn tell_fortune(&self) -> Bytes { - let rows = self.cl.query_raw(&self.fortune, &[]).await.unwrap(); + let fut = self.cl.query_raw(&self.fortune, &[]); - let mut fortunes = Vec::with_capacity(rows.len() + 1); - fortunes.push(Fortune { + let rows = fut.await.unwrap(); + let mut fortunes: SmallVec<[_; 32]> = smallvec::smallvec![Fortune { id: 0, - message: "Additional fortune added at request time.", - }); - fortunes.extend(rows.iter().map(|row| Fortune { - id: row.get(0), - message: row.get(1), - })); - fortunes.sort_by(|it, next| it.message.cmp(next.message)); + message: Cow::Borrowed("Additional fortune added at request time."), + }]; + + for row in rows { + fortunes.push(Fortune { + id: row.get(0), + message: Cow::Owned(row.get(1)), + }); + } + + fortunes.sort_by(|it, next| it.message.cmp(&next.message)); let mut body = std::mem::replace(&mut *self.buf.borrow_mut(), BytesMut::new()); utils::reserve(&mut body, 8 * 1024); diff --git a/frameworks/Rust/ntex/src/main.rs b/frameworks/Rust/ntex/src/main.rs index c9fd1e80245..c456fac47e4 100644 --- a/frameworks/Rust/ntex/src/main.rs +++ b/frameworks/Rust/ntex/src/main.rs @@ -1,5 +1,6 @@ #[global_allocator] -static GLOBAL: snmalloc_rs::SnMalloc = snmalloc_rs::SnMalloc; +static GLOBAL: mimalloc::MiMalloc = mimalloc::MiMalloc; +// static GLOBAL: snmalloc_rs::SnMalloc = snmalloc_rs::SnMalloc; use ntex::http::header::{CONTENT_TYPE, SERVER}; use ntex::{http, time::Seconds, util::BytesMut, util::PoolId, web}; diff --git a/frameworks/Rust/ntex/src/main_db.rs b/frameworks/Rust/ntex/src/main_db.rs index 437fd70b9e1..78c21fa7132 100644 --- a/frameworks/Rust/ntex/src/main_db.rs +++ b/frameworks/Rust/ntex/src/main_db.rs @@ -1,7 +1,7 @@ #[cfg(not(target_os = "macos"))] #[global_allocator] -static GLOBAL: snmalloc_rs::SnMalloc = snmalloc_rs::SnMalloc; -// static GLOBAL: mimalloc::MiMalloc = mimalloc::MiMalloc; +static GLOBAL: mimalloc::MiMalloc = mimalloc::MiMalloc; +// static GLOBAL: snmalloc_rs::SnMalloc = snmalloc_rs::SnMalloc; use ntex::http::header::{CONTENT_TYPE, SERVER}; use ntex::http::{HttpService, KeepAlive, Request, Response, StatusCode}; diff --git a/frameworks/Rust/ntex/src/main_plt.rs b/frameworks/Rust/ntex/src/main_plt.rs index cda9b69fa15..2f46ce448e1 100644 --- a/frameworks/Rust/ntex/src/main_plt.rs +++ b/frameworks/Rust/ntex/src/main_plt.rs @@ -1,5 +1,6 @@ #[global_allocator] static GLOBAL: snmalloc_rs::SnMalloc = snmalloc_rs::SnMalloc; + use std::{future::Future, io, pin::Pin, task::Context, task::Poll}; use ntex::{fn_service, http::h1, io::Io, io::RecvError, util::ready, util::PoolId}; From 990e3132698841deed4cac1f3d0c637de640ff20 Mon Sep 17 00:00:00 2001 From: Anton Kirilov Date: Tue, 13 Aug 2024 20:44:06 +0100 Subject: [PATCH 070/204] Update H2O to revision c54c63285 (#9205) --- frameworks/C/h2o/h2o.dockerfile | 2 +- frameworks/C/h2o/src/handlers/world.c | 6 ++++-- frameworks/PHP/php/php-h2o.dockerfile | 2 +- frameworks/Ruby/h2o_mruby/h2o_mruby.dockerfile | 2 +- 4 files changed, 7 insertions(+), 5 deletions(-) diff --git a/frameworks/C/h2o/h2o.dockerfile b/frameworks/C/h2o/h2o.dockerfile index bca0d12b19e..3b383b7f6df 100644 --- a/frameworks/C/h2o/h2o.dockerfile +++ b/frameworks/C/h2o/h2o.dockerfile @@ -33,7 +33,7 @@ RUN apt-get -yqq update && \ ruby \ systemtap-sdt-dev -ARG H2O_VERSION=18b175f71ede08b50d3e5ae8303dacef3ea510fc +ARG H2O_VERSION=c54c63285b52421da2782f028022647fc2ea3dd1 WORKDIR /tmp/h2o-build RUN curl -LSs "https://github.com/h2o/h2o/archive/${H2O_VERSION}.tar.gz" | \ diff --git a/frameworks/C/h2o/src/handlers/world.c b/frameworks/C/h2o/src/handlers/world.c index 82d29ce08b8..84088a25d42 100644 --- a/frameworks/C/h2o/src/handlers/world.c +++ b/frameworks/C/h2o/src/handlers/world.c @@ -238,8 +238,10 @@ static int do_multiple_queries(bool do_update, bool use_cache, h2o_req_t *req) const size_t num_query = get_query_number(req); // MAX_QUERIES is a relatively small number, say less than or equal to UINT16_MAX, so assume no - // overflow in the following arithmetic operations. - assert(num_query && num_query <= MAX_QUERIES && num_query <= UINT16_MAX); + // unsigned overflow in the following arithmetic operations. + static_assert(MAX_QUERIES <= UINT16_MAX, + "potential out-of-bounds memory accesses in the following code"); + assert(num_query && num_query <= MAX_QUERIES); size_t base_size = offsetof(multiple_query_ctx_t, res) + num_query * sizeof(query_result_t); diff --git a/frameworks/PHP/php/php-h2o.dockerfile b/frameworks/PHP/php/php-h2o.dockerfile index 57571b6b3c7..3de194e526b 100644 --- a/frameworks/PHP/php/php-h2o.dockerfile +++ b/frameworks/PHP/php/php-h2o.dockerfile @@ -4,7 +4,7 @@ ARG H2O_PREFIX=/opt/h2o FROM "ubuntu:${UBUNTU_VERSION}" AS compile -ARG H2O_VERSION=18b175f71ede08b50d3e5ae8303dacef3ea510fc +ARG H2O_VERSION=c54c63285b52421da2782f028022647fc2ea3dd1 ARG DEBIAN_FRONTEND=noninteractive ARG H2O_PREFIX diff --git a/frameworks/Ruby/h2o_mruby/h2o_mruby.dockerfile b/frameworks/Ruby/h2o_mruby/h2o_mruby.dockerfile index 7cc59cf699f..cdfbf5811b2 100644 --- a/frameworks/Ruby/h2o_mruby/h2o_mruby.dockerfile +++ b/frameworks/Ruby/h2o_mruby/h2o_mruby.dockerfile @@ -4,7 +4,7 @@ ARG H2O_PREFIX=/opt/h2o FROM "ubuntu:${UBUNTU_VERSION}" AS compile -ARG H2O_VERSION=18b175f71ede08b50d3e5ae8303dacef3ea510fc +ARG H2O_VERSION=c54c63285b52421da2782f028022647fc2ea3dd1 ARG DEBIAN_FRONTEND=noninteractive ARG H2O_PREFIX From 61305905d2f13d1490f86e0fc925237f820fddeb Mon Sep 17 00:00:00 2001 From: Joan Miquel Date: Tue, 13 Aug 2024 21:44:16 +0200 Subject: [PATCH 071/204] Fix bottle (#9203) --- frameworks/Python/bottle/benchmark_config.json | 3 ++- frameworks/Python/bottle/bottle-raw.dockerfile | 2 +- frameworks/Python/bottle/bottle.dockerfile | 2 +- frameworks/Python/bottle/requirements.txt | 4 ++-- 4 files changed, 6 insertions(+), 5 deletions(-) diff --git a/frameworks/Python/bottle/benchmark_config.json b/frameworks/Python/bottle/benchmark_config.json index e37735b8353..c895cf1e4e7 100644 --- a/frameworks/Python/bottle/benchmark_config.json +++ b/frameworks/Python/bottle/benchmark_config.json @@ -45,7 +45,8 @@ "database_os": "Linux", "display_name": "Bottle", "notes": "PyPy2", - "versus": "wsgi" + "versus": "wsgi", + "tags": ["broken"] }, "raw": { "db_url": "/raw-db", diff --git a/frameworks/Python/bottle/bottle-raw.dockerfile b/frameworks/Python/bottle/bottle-raw.dockerfile index 24a59598829..8ba573a7a2b 100644 --- a/frameworks/Python/bottle/bottle-raw.dockerfile +++ b/frameworks/Python/bottle/bottle-raw.dockerfile @@ -1,4 +1,4 @@ -FROM python:3.6.6-stretch +FROM python:3.9-bookworm WORKDIR /bottle COPY views views diff --git a/frameworks/Python/bottle/bottle.dockerfile b/frameworks/Python/bottle/bottle.dockerfile index 24a59598829..8ba573a7a2b 100644 --- a/frameworks/Python/bottle/bottle.dockerfile +++ b/frameworks/Python/bottle/bottle.dockerfile @@ -1,4 +1,4 @@ -FROM python:3.6.6-stretch +FROM python:3.9-bookworm WORKDIR /bottle COPY views views diff --git a/frameworks/Python/bottle/requirements.txt b/frameworks/Python/bottle/requirements.txt index 25c2d97e91a..7f6135dbd5b 100644 --- a/frameworks/Python/bottle/requirements.txt +++ b/frameworks/Python/bottle/requirements.txt @@ -1,6 +1,6 @@ -bottle==0.12.19 +bottle==0.12.25 bottle-sqlalchemy==0.4.3 -greenlet==0.4.14 +greenlet==0.4.17 gunicorn==19.9.0 meinheld==1.0.2 mysqlclient==1.3.12 From 094e02d6e4e3facfbe27fed0370464c63df5cdc0 Mon Sep 17 00:00:00 2001 From: fakeshadow <24548779@qq.com> Date: Wed, 14 Aug 2024 03:44:26 +0800 Subject: [PATCH 072/204] [xitca-web] update dep. (#9201) --- frameworks/Rust/xitca-web/Cargo.lock | 487 ++++++++++-------- frameworks/Rust/xitca-web/Cargo.toml | 18 +- frameworks/Rust/xitca-web/src/main_iou.rs | 2 +- frameworks/Rust/xitca-web/src/util.rs | 4 +- .../Rust/xitca-web/xitca-web-axum.dockerfile | 2 +- .../Rust/xitca-web/xitca-web-iou.dockerfile | 4 +- .../Rust/xitca-web/xitca-web-sync.dockerfile | 2 +- .../Rust/xitca-web/xitca-web.dockerfile | 2 +- 8 files changed, 274 insertions(+), 247 deletions(-) diff --git a/frameworks/Rust/xitca-web/Cargo.lock b/frameworks/Rust/xitca-web/Cargo.lock index 0bce6f973f8..e510a6c31dc 100644 --- a/frameworks/Rust/xitca-web/Cargo.lock +++ b/frameworks/Rust/xitca-web/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "addr2line" -version = "0.21.0" +version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" +checksum = "6e4503c46a5c0c7844e948c9a4d6acd9f50cccb4de1c48eb9e291ea17470c678" dependencies = [ "gimli", ] @@ -19,9 +19,9 @@ checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" [[package]] name = "async-trait" -version = "0.1.80" +version = "0.1.81" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6fa2087f2753a7da8cc1c0dbfcf89579dd57458e36769de5ac750b4671737ca" +checksum = "6e0c28dcc82d7c8ead5cb13beb15405b57b8546e93215673ff8ca0349a028107" dependencies = [ "proc-macro2", "quote", @@ -95,9 +95,9 @@ dependencies = [ [[package]] name = "backtrace" -version = "0.3.71" +version = "0.3.73" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26b05800d2e817c8b3b4b54abd461726265fa9789ae34330622f2db9ee696f9d" +checksum = "5cc23269a4f8976d0a4d2e7109211a419fe30e8d88d677cd60b6bc79c5732e0a" dependencies = [ "addr2line", "cc", @@ -110,9 +110,9 @@ dependencies = [ [[package]] name = "base64" -version = "0.21.7" +version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" [[package]] name = "bitflags" @@ -122,9 +122,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.5.0" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" +checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" [[package]] name = "block-buffer" @@ -143,15 +143,15 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.6.0" +version = "1.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9" +checksum = "8318a53db07bb3f8dca91a600466bdb3f2eaadeedfdbcf02e1accbad9271ba50" [[package]] name = "cc" -version = "1.0.98" +version = "1.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41c270e7540d725e65ac7f1b212ac8ce349719624d7bcff99f8e2e488e8cf03f" +checksum = "504bdec147f2cc13c8b57ed9401fd8a147cc66b67ad5cb241394244f2c947549" [[package]] name = "cfg-if" @@ -178,13 +178,48 @@ dependencies = [ "typenum", ] +[[package]] +name = "darling" +version = "0.20.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f63b86c8a8826a49b8c21f08a2d07338eec8d900540f8630dc76284be802989" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.20.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95133861a8032aaea082871032f5815eb9e98cef03fa916ab4500513994df9e5" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn", +] + +[[package]] +name = "darling_macro" +version = "0.20.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" +dependencies = [ + "darling_core", + "quote", + "syn", +] + [[package]] name = "diesel" -version = "2.1.6" +version = "2.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff236accb9a5069572099f0b350a92e9560e8e63a9b8d546162f4a5e03026bb2" +checksum = "bf97ee7261bb708fa3402fa9c17a54b70e90e3cb98afb3dc8999d5512cb03f94" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.6.0", "byteorder", "diesel_derives", "itoa", @@ -194,11 +229,12 @@ dependencies = [ [[package]] name = "diesel_derives" -version = "2.1.4" +version = "2.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14701062d6bed917b5c7103bdffaee1e4609279e240488ad24e7bd979ca6866c" +checksum = "d6ff2be1e7312c858b2ef974f5c7089833ae57b5311b334b30923af58e5718d8" dependencies = [ "diesel_table_macro_syntax", + "dsl_auto_type", "proc-macro2", "quote", "syn", @@ -206,9 +242,9 @@ dependencies = [ [[package]] name = "diesel_table_macro_syntax" -version = "0.1.0" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc5557efc453706fed5e4fa85006fe9817c224c3f480a34c7e5959fd700921c5" +checksum = "209c735641a413bc68c4923a9d6ad4bcb3ca306b794edaa7eb0b3228a99ffb25" dependencies = [ "syn", ] @@ -224,6 +260,26 @@ dependencies = [ "subtle", ] +[[package]] +name = "dsl_auto_type" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5d9abe6314103864cc2d8901b7ae224e0ab1a103a0a416661b4097b0779b607" +dependencies = [ + "darling", + "either", + "heck", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "either" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" + [[package]] name = "fallible-iterator" version = "0.2.0" @@ -232,22 +288,16 @@ checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7" [[package]] name = "filetime" -version = "0.2.23" +version = "0.2.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ee447700ac8aa0b2f2bd7bc4462ad686ba06baa6727ac149a2d6277f0d240fd" +checksum = "bf401df4a4e3872c4fe8151134cf483738e74b67fc934d6532c882b3d24a4550" dependencies = [ "cfg-if", "libc", - "redox_syscall 0.4.1", - "windows-sys 0.52.0", + "libredox", + "windows-sys 0.59.0", ] -[[package]] -name = "finl_unicode" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fcfdc7a0362c9f4444381a9e697c79d435fe65b52a37466fc2c1184cee9edc6" - [[package]] name = "fnv" version = "1.0.7" @@ -285,6 +335,7 @@ dependencies = [ "futures-task", "pin-project-lite", "pin-utils", + "slab", ] [[package]] @@ -310,9 +361,15 @@ dependencies = [ [[package]] name = "gimli" -version = "0.28.1" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" +checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd" + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" [[package]] name = "hermit-abi" @@ -351,9 +408,9 @@ dependencies = [ [[package]] name = "http-body" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cac85db508abc24a2e48553ba12a996e87244a0395ce011e62b37158745d643" +checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" dependencies = [ "bytes", "http", @@ -361,12 +418,12 @@ dependencies = [ [[package]] name = "http-body-util" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0475f8b2ac86659c21b64320d5d653f9efe42acd2a4e560073ec61a155a34f1d" +checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f" dependencies = [ "bytes", - "futures-core", + "futures-util", "http", "http-body", "pin-project-lite", @@ -374,9 +431,9 @@ dependencies = [ [[package]] name = "httparse" -version = "1.8.0" +version = "1.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" +checksum = "0fcc0b4a115bf80b728eb8ea024ad5bd707b615bfed49e0665b6e0f86fd082d9" [[package]] name = "httpdate" @@ -384,11 +441,17 @@ version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + [[package]] name = "io-uring" -version = "0.5.13" +version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd1e1a01cfb924fd8c5c43b6827965db394f5a3a16c599ce03452266e1cf984c" +checksum = "595a0399f411a508feb2ec1e970a4a30c249351e30208960d58298de8660b0e5" dependencies = [ "bitflags 1.3.2", "libc", @@ -414,14 +477,25 @@ checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" [[package]] name = "libmimalloc-sys" -version = "0.1.38" +version = "0.1.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e7bb23d733dfcc8af652a78b7bf232f0e967710d044732185e561e47c0336b6" +checksum = "23aa6811d3bd4deb8a84dde645f943476d13b248d818edcf8ce0b2f37f036b44" dependencies = [ "cc", "libc", ] +[[package]] +name = "libredox" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" +dependencies = [ + "bitflags 2.6.0", + "libc", + "redox_syscall", +] + [[package]] name = "lock_api" version = "0.4.12" @@ -434,9 +508,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.21" +version = "0.4.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" +checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" [[package]] name = "matchit" @@ -456,15 +530,15 @@ dependencies = [ [[package]] name = "memchr" -version = "2.7.2" +version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "mimalloc" -version = "0.1.42" +version = "0.1.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9186d86b79b52f4a77af65604b51225e8db1d6ee7e3f41aec1e40829c71a176" +checksum = "68914350ae34959d83f732418d51e2427a794055d0b9529f48259ac07af65633" dependencies = [ "libmimalloc-sys", ] @@ -477,22 +551,23 @@ checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" [[package]] name = "miniz_oxide" -version = "0.7.3" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87dfd01fe195c66b572b37921ad8803d010623c0aca821bea2302239d155cdae" +checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08" dependencies = [ "adler", ] [[package]] name = "mio" -version = "0.8.11" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" +checksum = "4569e456d394deccd22ce1c1913e6ea0e54519f577285001215d33557431afe4" dependencies = [ + "hermit-abi", "libc", "wasi", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] @@ -510,21 +585,11 @@ dependencies = [ "autocfg", ] -[[package]] -name = "num_cpus" -version = "1.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" -dependencies = [ - "hermit-abi", - "libc", -] - [[package]] name = "object" -version = "0.32.2" +version = "0.36.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441" +checksum = "27b64972346851a39438c60b341ebc01bba47464ae329e55cf343eb93964efd9" dependencies = [ "memchr", ] @@ -537,9 +602,9 @@ checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" [[package]] name = "parking_lot" -version = "0.12.2" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e4af0ca4f6caed20e900d564c242b8e5d4903fdacf31d3daf527b66fe6f42fb" +checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" dependencies = [ "lock_api", "parking_lot_core", @@ -553,9 +618,9 @@ checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" dependencies = [ "cfg-if", "libc", - "redox_syscall 0.5.1", + "redox_syscall", "smallvec", - "windows-targets 0.52.5", + "windows-targets", ] [[package]] @@ -598,9 +663,9 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "postgres-protocol" -version = "0.6.6" +version = "0.6.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49b6c5ef183cd3ab4ba005f1ca64c21e8bd97ce4699cfea9e8d9a2c4958ca520" +checksum = "acda0ebdebc28befa84bee35e651e4c5f09073d668c7aed4cf7e23c3cda84b23" dependencies = [ "base64", "byteorder", @@ -616,9 +681,9 @@ dependencies = [ [[package]] name = "postgres-types" -version = "0.2.6" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d2234cdee9408b523530a9b6d2d6b373d1db34f6a8e51dc03ded1828d7fb67c" +checksum = "02048d9e032fb3cc3413bbf7b83a15d84a5d419778e2628751896d856498eee9" dependencies = [ "bytes", "fallible-iterator", @@ -627,24 +692,27 @@ dependencies = [ [[package]] name = "ppv-lite86" -version = "0.2.17" +version = "0.2.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" +checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" +dependencies = [ + "zerocopy", +] [[package]] name = "pq-sys" -version = "0.4.8" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31c0052426df997c0cbd30789eb44ca097e3541717a7b8fa36b1c464ee7edebd" +checksum = "a24ff9e4cf6945c988f0db7005d87747bf72864965c3529d259ad155ac41d584" dependencies = [ "vcpkg", ] [[package]] name = "proc-macro2" -version = "1.0.83" +version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b33eb56c327dec362a9e55b3ad14f9d2f0904fb5a5b03b513ab5465399e9f43" +checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" dependencies = [ "unicode-ident", ] @@ -701,20 +769,11 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.4.1" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" +checksum = "2a908a6e00f1fdd0dfd9c0eb08ce85126f6d8bbda50017e74bc4a4b7d4a926a4" dependencies = [ - "bitflags 1.3.2", -] - -[[package]] -name = "redox_syscall" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "469052894dcb553421e483e4209ee581a45100d31b4018de03e5a7ad86374a7e" -dependencies = [ - "bitflags 2.5.0", + "bitflags 2.6.0", ] [[package]] @@ -780,12 +839,6 @@ dependencies = [ "parking_lot", ] -[[package]] -name = "scoped-tls" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" - [[package]] name = "scopeguard" version = "1.2.0" @@ -794,18 +847,18 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "serde" -version = "1.0.202" +version = "1.0.205" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "226b61a0d411b2ba5ff6d7f73a476ac4f8bb900373459cd00fab8512828ba395" +checksum = "e33aedb1a7135da52b7c21791455563facbbcc43d0f0f66165b42c21b3dfb150" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.202" +version = "1.0.205" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6048858004bcff69094cd972ed40a32500f153bd3be9f716b2eed2e8217c4838" +checksum = "692d6f5ac90220161d6774db30c662202721e64aed9058d2c394f451261420c1" dependencies = [ "proc-macro2", "quote", @@ -814,11 +867,12 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.117" +version = "1.0.122" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "455182ea6142b14f93f4bc5320a2b31c1f266b66a4a5c858b013302a5d8cbfc3" +checksum = "784b6203951c57ff748476b126ccb5e8e2959a5c19e5c617ab1956be3dbc68da" dependencies = [ "itoa", + "memchr", "ryu", "serde", ] @@ -902,26 +956,32 @@ dependencies = [ [[package]] name = "stringprep" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb41d74e231a107a1b4ee36bd1214b11285b77768d2e3824aedafa988fd36ee6" +checksum = "7b4df3d392d81bd458a8a621b8bffbd2302a12ffe288a9d931670948749463b1" dependencies = [ - "finl_unicode", "unicode-bidi", "unicode-normalization", + "unicode-properties", ] +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + [[package]] name = "subtle" -version = "2.5.0" +version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "syn" -version = "2.0.65" +version = "2.0.72" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2863d96a84c6439701d7a38f9de935ec562c8832cc55d1dde0f513b52fad106" +checksum = "dc4b9b9bf2add8093d3f2c0204471e951b2285580335de42f9d2534f3ae7a8af" dependencies = [ "proc-macro2", "quote", @@ -942,9 +1002,9 @@ checksum = "a7065abeca94b6a8a577f9bd45aa0867a2238b74e8eb67cf10d492bc39351394" [[package]] name = "tinyvec" -version = "1.6.0" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +checksum = "445e881f4f6d382d5f27c034e25eb92edd7c784ceab92a0937db7f2e9471b938" dependencies = [ "tinyvec_macros", ] @@ -957,31 +1017,30 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.37.0" +version = "1.39.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1adbebffeca75fcfd058afa480fb6c0b81e165a0323f9c9d39c9697e37c46787" +checksum = "daa4fb1bc778bd6f04cbfc4bb2d06a7396a8f299dc33ea1900cedaa316f467b1" dependencies = [ "backtrace", "libc", "mio", - "num_cpus", "parking_lot", "pin-project-lite", "signal-hook-registry", "socket2 0.5.7", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] name = "tokio-uring" -version = "0.4.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d5e02bb137e030b3a547c65a3bd2f1836d66a97369fdcc69034002b10e155ef" +checksum = "748482e3e13584a34664a710168ad5068e8cb1d968aa4ffa887e83ca6dd27967" dependencies = [ "bytes", + "futures-util", "io-uring", "libc", - "scoped-tls", "slab", "socket2 0.4.10", "tokio", @@ -1008,7 +1067,7 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e9cd434a998747dd2c4276bc96ee2e0c7a2eadf3cae88e52be55a05fa9053f5" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.6.0", "bytes", "http", "http-body", @@ -1077,6 +1136,12 @@ dependencies = [ "tinyvec", ] +[[package]] +name = "unicode-properties" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4259d9d4425d9f0661581b804cb85fe66a4c631cadd8f490d1c13a35d5d9291" + [[package]] name = "vcpkg" version = "0.2.15" @@ -1085,9 +1150,9 @@ checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" [[package]] name = "version_check" -version = "0.9.4" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" [[package]] name = "wasi" @@ -1117,150 +1182,93 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" -[[package]] -name = "windows-sys" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" -dependencies = [ - "windows-targets 0.48.5", -] - [[package]] name = "windows-sys" version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets 0.52.5", + "windows-targets", ] [[package]] -name = "windows-targets" -version = "0.48.5" +name = "windows-sys" +version = "0.59.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" dependencies = [ - "windows_aarch64_gnullvm 0.48.5", - "windows_aarch64_msvc 0.48.5", - "windows_i686_gnu 0.48.5", - "windows_i686_msvc 0.48.5", - "windows_x86_64_gnu 0.48.5", - "windows_x86_64_gnullvm 0.48.5", - "windows_x86_64_msvc 0.48.5", + "windows-targets", ] [[package]] name = "windows-targets" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ - "windows_aarch64_gnullvm 0.52.5", - "windows_aarch64_msvc 0.52.5", - "windows_i686_gnu 0.52.5", + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", "windows_i686_gnullvm", - "windows_i686_msvc 0.52.5", - "windows_x86_64_gnu 0.52.5", - "windows_x86_64_gnullvm 0.52.5", - "windows_x86_64_msvc 0.52.5", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", ] [[package]] name = "windows_aarch64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.52.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.48.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" [[package]] name = "windows_aarch64_msvc" -version = "0.52.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" - -[[package]] -name = "windows_i686_gnu" -version = "0.48.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" [[package]] name = "windows_i686_gnu" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" [[package]] name = "windows_i686_gnullvm" -version = "0.52.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" - -[[package]] -name = "windows_i686_msvc" -version = "0.48.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" [[package]] name = "windows_i686_msvc" -version = "0.52.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.48.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" [[package]] name = "windows_x86_64_gnu" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" [[package]] name = "windows_x86_64_gnullvm" -version = "0.48.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.52.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" [[package]] name = "windows_x86_64_msvc" -version = "0.48.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.52.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "xitca-codegen" -version = "0.2.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "866906a5f280481ef022ccdec1640730550304bb86b016815d9982fde2f48e3e" +checksum = "336b646a30e6d44093beaae1bbe5dda664e8466d387663fc9d61c55fb2d78424" dependencies = [ "quote", "syn", @@ -1268,9 +1276,9 @@ dependencies = [ [[package]] name = "xitca-http" -version = "0.5.0" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d5fd258cd6cd9d677cb94273da69fafee7460bbbd001c92a73c167149856e46" +checksum = "47b5b036e32261c69d4f0e81bcb28c2e058ed569518959336fd75fc086208d3f" dependencies = [ "futures-core", "http", @@ -1290,9 +1298,9 @@ dependencies = [ [[package]] name = "xitca-io" -version = "0.3.0" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da690dc253320dae7ffbb70e7fa9c5e52ef79476dd41f5d52b9114c8b58d7126" +checksum = "376a4849eef1f3475a6b7a5c474dac278c320a28f6e2abc07be57048b35cc5df" dependencies = [ "bytes", "tokio", @@ -1303,7 +1311,7 @@ dependencies = [ [[package]] name = "xitca-postgres" version = "0.1.0" -source = "git+https://github.com/HFQR/xitca-web.git?rev=ea1f5a2447e0969a6dff84eac9ff9ff90dbc7ed1#ea1f5a2447e0969a6dff84eac9ff9ff90dbc7ed1" +source = "git+https://github.com/HFQR/xitca-web.git?rev=0cad5309beb278dc967378a35b733e26be0d4073#0cad5309beb278dc967378a35b733e26be0d4073" dependencies = [ "fallible-iterator", "percent-encoding", @@ -1318,18 +1326,18 @@ dependencies = [ [[package]] name = "xitca-router" -version = "0.2.0" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "687a3fb0a32b89524fab7d780d4cc66942b8ee6a493a7f2ff78384fe677b8e09" +checksum = "35a771113f381c9a2f5ae1096b70d629ed241a1a473304ea902258c3d528f536" dependencies = [ "xitca-unsafe-collection", ] [[package]] name = "xitca-server" -version = "0.3.0" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e144aca50286d05f7450045d6b6eebe2157ed11bc5821d926fc276280113c94" +checksum = "a40a05f18780f1de843c5077583e4650b08d0518fcf9cf7948e28bc92e489736" dependencies = [ "socket2 0.5.7", "tokio", @@ -1342,15 +1350,15 @@ dependencies = [ [[package]] name = "xitca-service" -version = "0.1.0" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09a4a38548b14925111dd99560f0a10d1eb9e3e117fa5471c35387ed6f77b58c" +checksum = "74b093ca75b264924773d53e445de08a937100bf1cbe4f62d4dc2c0d04a3ba4b" [[package]] name = "xitca-unsafe-collection" -version = "0.1.1" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "552a6bf21a5d0dc470644cb3b99f98f44bd414cd6fcca74610465d8196b1d23e" +checksum = "467b95b08735dcd7061be626d02aea062bc0b99918bc9de11b8fc15d901158ae" dependencies = [ "bytes", ] @@ -1378,14 +1386,14 @@ dependencies = [ "xitca-server", "xitca-service", "xitca-unsafe-collection", - "xitca-web 0.5.0", + "xitca-web 0.6.2", ] [[package]] name = "xitca-web" -version = "0.5.0" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd23a9146a753f4f9e10bf4cc99b53d040a5459c32f043965d75f0c2b4a78af6" +checksum = "dd4f8f16791ea2a8845f617f1e87887f917835e0603d01f03a51e638b9613d0c" dependencies = [ "futures-core", "http-body", @@ -1402,3 +1410,24 @@ dependencies = [ "xitca-service", "xitca-unsafe-collection", ] + +[[package]] +name = "zerocopy" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" +dependencies = [ + "byteorder", + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] diff --git a/frameworks/Rust/xitca-web/Cargo.toml b/frameworks/Rust/xitca-web/Cargo.toml index b9447c3e7ea..d9606bf2a96 100644 --- a/frameworks/Rust/xitca-web/Cargo.toml +++ b/frameworks/Rust/xitca-web/Cargo.toml @@ -11,7 +11,7 @@ required-features = ["io-uring", "pg", "router", "template"] [[bin]] name = "xitca-web-iou" path = "./src/main_iou.rs" -required-features = ["io-uring", "perf", "pg-iou", "template"] +required-features = ["io-uring", "perf", "pg", "template"] [[bin]] name = "xitca-web-wasm" @@ -33,8 +33,6 @@ required-features = ["pg-orm", "template", "web-codegen"] pg = ["xitca-postgres/single-thread"] # pg send/sync optional pg-sync = ["xitca-postgres"] -# pg io_uring optional -pg-iou = ["pg", "xitca-postgres/io-uring"] # pg orm optional pg-orm = ["diesel"] # http router optional @@ -53,18 +51,18 @@ axum = ["dep:axum", "http-body", "tower", "tower-http", "xitca-web/tower-http-co perf = ["mimalloc", "tokio/parking_lot"] [dependencies] -xitca-http = "0.5" -xitca-io = "0.3" -xitca-server = "0.3" -xitca-service = "0.1" -xitca-unsafe-collection = "0.1.1" +xitca-http = "0.6" +xitca-io = "0.4" +xitca-server = "0.4" +xitca-service = "0.2" +xitca-unsafe-collection = "0.2" atoi = "2" serde = { version = "1" } serde_json = { version = "1" } # web optional -xitca-web = { version = "0.5", features = ["json"], optional = true } +xitca-web = { version = "0.6", features = ["json"], optional = true } # raw-pg optional xitca-postgres = { version = "0.1", optional = true } @@ -97,4 +95,4 @@ codegen-units = 1 panic = "abort" [patch.crates-io] -xitca-postgres = { git = "https://github.com/HFQR/xitca-web.git", rev = "ea1f5a2447e0969a6dff84eac9ff9ff90dbc7ed1" } +xitca-postgres = { git = "https://github.com/HFQR/xitca-web.git", rev = "0cad5309beb278dc967378a35b733e26be0d4073" } diff --git a/frameworks/Rust/xitca-web/src/main_iou.rs b/frameworks/Rust/xitca-web/src/main_iou.rs index 83dfbc0eaab..67ae6dad4d3 100644 --- a/frameworks/Rust/xitca-web/src/main_iou.rs +++ b/frameworks/Rust/xitca-web/src/main_iou.rs @@ -24,7 +24,7 @@ use xitca_http::{ }; use xitca_io::{ bytes::{Bytes, BytesMut}, - io_uring::IoBuf, + io_uring::BoundedBuf, net::{io_uring::TcpStream as IOUTcpStream, TcpStream}, }; use xitca_service::{fn_build, fn_service, middleware::UncheckedReady, Service, ServiceExt}; diff --git a/frameworks/Rust/xitca-web/src/util.rs b/frameworks/Rust/xitca-web/src/util.rs index 8c4cee9da98..dc0476a5d15 100755 --- a/frameworks/Rust/xitca-web/src/util.rs +++ b/frameworks/Rust/xitca-web/src/util.rs @@ -49,7 +49,7 @@ mod non_wasm { } } - #[cfg(any(feature = "pg", feature = "pg-iou"))] + #[cfg(feature = "pg")] mod pg_state { use core::{cell::RefCell, future::Future, pin::Pin}; @@ -79,7 +79,7 @@ mod non_wasm { } } - #[cfg(any(feature = "pg", feature = "pg-iou"))] + #[cfg(feature = "pg")] pub use pg_state::*; } diff --git a/frameworks/Rust/xitca-web/xitca-web-axum.dockerfile b/frameworks/Rust/xitca-web/xitca-web-axum.dockerfile index 2d29f5e2ffb..f5a87ea8ec5 100644 --- a/frameworks/Rust/xitca-web/xitca-web-axum.dockerfile +++ b/frameworks/Rust/xitca-web/xitca-web-axum.dockerfile @@ -1,4 +1,4 @@ -FROM rust:1.77 +FROM rust:1.79 ADD ./ /xitca-web WORKDIR /xitca-web diff --git a/frameworks/Rust/xitca-web/xitca-web-iou.dockerfile b/frameworks/Rust/xitca-web/xitca-web-iou.dockerfile index 43bf2b23fc5..3b0ef259420 100644 --- a/frameworks/Rust/xitca-web/xitca-web-iou.dockerfile +++ b/frameworks/Rust/xitca-web/xitca-web-iou.dockerfile @@ -1,9 +1,9 @@ -FROM rust:1.77 +FROM rust:1.79 ADD ./ /xitca-web WORKDIR /xitca-web -RUN cargo build --release --bin xitca-web-iou --features io-uring,perf,pg-iou,template +RUN cargo build --release --bin xitca-web-iou --features io-uring,perf,pg,template EXPOSE 8080 diff --git a/frameworks/Rust/xitca-web/xitca-web-sync.dockerfile b/frameworks/Rust/xitca-web/xitca-web-sync.dockerfile index 5e71fa5d649..21ed93620d3 100644 --- a/frameworks/Rust/xitca-web/xitca-web-sync.dockerfile +++ b/frameworks/Rust/xitca-web/xitca-web-sync.dockerfile @@ -1,4 +1,4 @@ -FROM rust:1.77 +FROM rust:1.79 ADD ./ /xitca-web WORKDIR /xitca-web diff --git a/frameworks/Rust/xitca-web/xitca-web.dockerfile b/frameworks/Rust/xitca-web/xitca-web.dockerfile index bed37320e72..0bbd89946c6 100644 --- a/frameworks/Rust/xitca-web/xitca-web.dockerfile +++ b/frameworks/Rust/xitca-web/xitca-web.dockerfile @@ -1,4 +1,4 @@ -FROM rust:1.77 +FROM rust:1.79 ADD ./ /xitca-web WORKDIR /xitca-web From db2f34b8eb6a2a87b8f3773f9fabb839db25b234 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 13 Aug 2024 19:44:35 +0000 Subject: [PATCH 073/204] Bump aiohttp from 3.9.4 to 3.10.2 in /frameworks/Python/aiohttp Bumps [aiohttp](https://github.com/aio-libs/aiohttp) from 3.9.4 to 3.10.2. - [Release notes](https://github.com/aio-libs/aiohttp/releases) - [Changelog](https://github.com/aio-libs/aiohttp/blob/master/CHANGES.rst) - [Commits](https://github.com/aio-libs/aiohttp/compare/v3.9.4...v3.10.2) --- updated-dependencies: - dependency-name: aiohttp dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- frameworks/Python/aiohttp/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frameworks/Python/aiohttp/requirements.txt b/frameworks/Python/aiohttp/requirements.txt index d0caf5f25e7..444a284f816 100644 --- a/frameworks/Python/aiohttp/requirements.txt +++ b/frameworks/Python/aiohttp/requirements.txt @@ -1,4 +1,4 @@ -aiohttp==3.9.4 +aiohttp==3.10.2 asyncpg==0.25.0 cchardet==2.1.7 gunicorn==20.1 From 1b2f23aa7c8a9cdd4d3ed1b9b3890b872288e30a Mon Sep 17 00:00:00 2001 From: Aaron Tavistock Date: Tue, 13 Aug 2024 12:50:42 -0700 Subject: [PATCH 074/204] [elixir] Version and code updates (#9198) * Updates for Phoenix, Elixir, Erlang, and Docker image * Missed on mix file and template should be heex * Add back fortunes with heex * Update plug libraries * Code based performance improvements --- .../Elixir/phoenix/benchmark_config.json | 29 +---------- frameworks/Elixir/phoenix/config/bandit.exs | 43 ---------------- frameworks/Elixir/phoenix/config/config.exs | 8 +++ frameworks/Elixir/phoenix/config/prod.exs | 9 ++-- .../Elixir/phoenix/lib/hello/application.ex | 2 +- frameworks/Elixir/phoenix/lib/hello/cache.ex | 5 -- .../Elixir/phoenix/lib/hello/world_cache.ex | 31 ++++++++++++ frameworks/Elixir/phoenix/lib/hello_web.ex | 4 +- .../hello_web/controllers/page_controller.ex | 36 ++++++------- .../{fortunes.html.eex => fortunes.html.heex} | 0 frameworks/Elixir/phoenix/mix.exs | 16 +++--- frameworks/Elixir/phoenix/mix.lock | 50 +++++++++---------- .../Elixir/phoenix/phoenix-bandit.dockerfile | 39 --------------- frameworks/Elixir/phoenix/phoenix.dockerfile | 6 +-- .../Elixir/plug/elixir-plug-ecto.dockerfile | 6 +-- frameworks/Elixir/plug/mix.exs | 12 ++--- frameworks/Elixir/plug/mix.lock | 34 ++++++------- 17 files changed, 123 insertions(+), 207 deletions(-) delete mode 100644 frameworks/Elixir/phoenix/config/bandit.exs delete mode 100644 frameworks/Elixir/phoenix/lib/hello/cache.ex create mode 100644 frameworks/Elixir/phoenix/lib/hello/world_cache.ex rename frameworks/Elixir/phoenix/lib/hello_web/controllers/page_html/{fortunes.html.eex => fortunes.html.heex} (100%) delete mode 100644 frameworks/Elixir/phoenix/phoenix-bandit.dockerfile diff --git a/frameworks/Elixir/phoenix/benchmark_config.json b/frameworks/Elixir/phoenix/benchmark_config.json index 9af25b9fbdc..2286bd85fbd 100644 --- a/frameworks/Elixir/phoenix/benchmark_config.json +++ b/frameworks/Elixir/phoenix/benchmark_config.json @@ -2,30 +2,6 @@ "framework": "phoenix", "tests": [{ "default": { - "json_url": "/json", - "db_url": "/db", - "query_url": "/queries?queries=", - "fortune_url": "/fortunes", - "plaintext_url": "/plaintext", - "update_url": "/updates?queries=", - "cached_query_url": "/cached-queries?count=", - "port": 8080, - "approach": "Realistic", - "classification": "Fullstack", - "database": "Postgres", - "framework": "Phoenix", - "language": "Elixir", - "flavor": "None", - "orm": "full", - "platform": "beam", - "webserver": "cowboy", - "os": "Linux", - "database_os": "Linux", - "display_name": "Phoenix", - "notes": "", - "versus": "" - }, - "bandit": { "json_url": "/json", "db_url": "/db", "query_url": "/queries?queries=", @@ -45,9 +21,8 @@ "webserver": "bandit", "os": "Linux", "database_os": "Linux", - "display_name": "Phoenix-Bandit", - "notes": "", - "versus": "default" + "display_name": "Phoenix", + "notes": "" } }] } diff --git a/frameworks/Elixir/phoenix/config/bandit.exs b/frameworks/Elixir/phoenix/config/bandit.exs deleted file mode 100644 index ccaf648c115..00000000000 --- a/frameworks/Elixir/phoenix/config/bandit.exs +++ /dev/null @@ -1,43 +0,0 @@ -import Config - -config :hello, HelloWeb.Endpoint, - adapter: Bandit.PhoenixAdapter, - http: [port: 8080, ip: {0, 0, 0, 0}], - cache_static_lookup: false, - check_orgin: false, - debug_errors: false, - code_reloader: false, - server: true - - -config :hello, Hello.Repo, - username: "benchmarkdbuser", - password: "benchmarkdbpass", - database: "hello_world", - hostname: "tfb-database", - pool_size: 40, - queue_target: 5000, - log: false - -config :phoenix, :logger, false - -config :logger, - compile_time_purge_matching: [ - [level_lower_than: :error] - ], - level: :error, - backends: [] - -# ## SSL Support -# -# To get SSL working, you will need to add the `https` key -# to the previous section: -# -# config:hello, Hello.Endpoint, -# ... -# https: [port: 443, -# keyfile: System.get_env("SOME_APP_SSL_KEY_PATH"), -# certfile: System.get_env("SOME_APP_SSL_CERT_PATH")] -# -# Where those two env variables point to a file on -# disk for the key and cert. diff --git a/frameworks/Elixir/phoenix/config/config.exs b/frameworks/Elixir/phoenix/config/config.exs index be5688f535b..e464e49d164 100755 --- a/frameworks/Elixir/phoenix/config/config.exs +++ b/frameworks/Elixir/phoenix/config/config.exs @@ -18,6 +18,14 @@ config :hello, HelloWeb.Endpoint, debug_errors: false, secret_key_base: "Z18ZjzZslFpKd8HB41IljqMavPiOKVF9y1DIQ+S2Ytg7Op0EIauwJgd7mtRStssx" +# Configure cache for world entities +config :hello, Hello.WorldCache, + gc_interval: :timer.hours(1), + max_size: 1_000_000, + allocated_memory: 100_000_000, + gc_cleanup_min_timeout: :timer.seconds(30), + gc_cleanup_max_timeout: :timer.minutes(30) + # Configures Elixir's Logger config :logger, :console, format: "$time $metadata[$level] $message\n", diff --git a/frameworks/Elixir/phoenix/config/prod.exs b/frameworks/Elixir/phoenix/config/prod.exs index 853a5ea247d..48b24364a40 100755 --- a/frameworks/Elixir/phoenix/config/prod.exs +++ b/frameworks/Elixir/phoenix/config/prod.exs @@ -1,9 +1,10 @@ import Config config :hello, HelloWeb.Endpoint, - url: [host: "0.0.0.0"], - http: [port: 8080, protocol_options: [max_keepalive: :infinity], backlog: 8096], - cache_static_lookup: false, + adapter: Bandit.PhoenixAdapter, + http: [port: 8080, ip: {0, 0, 0, 0}], + http_options: [log_protocol_errors: false], + compress: false, check_origin: false, debug_errors: false, code_reloader: false, @@ -14,7 +15,7 @@ config :hello, Hello.Repo, password: "benchmarkdbpass", database: "hello_world", hostname: "tfb-database", - pool_size: 40, + pool_size: 50, queue_target: 5000, log: false diff --git a/frameworks/Elixir/phoenix/lib/hello/application.ex b/frameworks/Elixir/phoenix/lib/hello/application.ex index 58fed15fc63..49f1ef8ba03 100644 --- a/frameworks/Elixir/phoenix/lib/hello/application.ex +++ b/frameworks/Elixir/phoenix/lib/hello/application.ex @@ -6,7 +6,7 @@ defmodule Hello.Application do def start(_type, _args) do children = [ Hello.Repo, - {Hello.Cache, []}, + {Hello.WorldCache, []}, HelloWeb.Endpoint ] diff --git a/frameworks/Elixir/phoenix/lib/hello/cache.ex b/frameworks/Elixir/phoenix/lib/hello/cache.ex deleted file mode 100644 index 0f051a3fb72..00000000000 --- a/frameworks/Elixir/phoenix/lib/hello/cache.ex +++ /dev/null @@ -1,5 +0,0 @@ -defmodule Hello.Cache do - use Nebulex.Cache, - otp_app: :hello, - adapter: Nebulex.Adapters.Local -end diff --git a/frameworks/Elixir/phoenix/lib/hello/world_cache.ex b/frameworks/Elixir/phoenix/lib/hello/world_cache.ex new file mode 100644 index 00000000000..b4943e14a35 --- /dev/null +++ b/frameworks/Elixir/phoenix/lib/hello/world_cache.ex @@ -0,0 +1,31 @@ +defmodule Hello.WorldCache do + use Nebulex.Cache, + otp_app: :hello, + adapter: Nebulex.Adapters.Local + + alias Hello.Models.World + alias Hello.Repo + + def seed do + if not __MODULE__.has_key?(:seeded) do + World + |> Repo.all() + |> Enum.into([], &{&1.id, &1}) + |> __MODULE__.put_all() + + __MODULE__.put(:seeded, true) + end + end + + def fetch(id) do + case __MODULE__.get(id) do + nil -> + world = Repo.get(World, id) + :ok = __MODULE__.put(id, world) + world + world -> + world + end + end + +end diff --git a/frameworks/Elixir/phoenix/lib/hello_web.ex b/frameworks/Elixir/phoenix/lib/hello_web.ex index 78062f969be..1193aab23a5 100644 --- a/frameworks/Elixir/phoenix/lib/hello_web.ex +++ b/frameworks/Elixir/phoenix/lib/hello_web.ex @@ -62,9 +62,7 @@ defmodule HelloWeb do defp html_helpers do quote do # Use all HTML functionality (forms, tags, etc) - use Phoenix.HTML - # Core UI Components and translation - import HelloWeb.Gettext + import Phoenix.HTML # Routes generation with the ~p sigil unquote(verified_routes()) diff --git a/frameworks/Elixir/phoenix/lib/hello_web/controllers/page_controller.ex b/frameworks/Elixir/phoenix/lib/hello_web/controllers/page_controller.ex index a44c5edf099..34c1fc120fd 100644 --- a/frameworks/Elixir/phoenix/lib/hello_web/controllers/page_controller.ex +++ b/frameworks/Elixir/phoenix/lib/hello_web/controllers/page_controller.ex @@ -1,10 +1,11 @@ defmodule HelloWeb.PageController do - alias Hello.Models.{Fortune, World} use HelloWeb, :controller + alias Hello.Models.Fortune + alias Hello.Models.World alias Hello.Repo - alias Hello.Cache + alias Hello.WorldCache @random_max 10_000 @@ -29,7 +30,7 @@ defmodule HelloWeb.PageController do worlds = Stream.repeatedly(&random_id/0) |> Stream.uniq() - |> Stream.map(fn idx -> Repo.get(World, idx) end) + |> Stream.map(&Repo.get(World, &1)) |> Enum.take(size(params["queries"])) json(conn, worlds) @@ -41,11 +42,11 @@ defmodule HelloWeb.PageController do message: "Additional fortune added at request time." } - fortunes = [additional_fortune | Repo.all(Fortune)] + fortunes = + [additional_fortune | Repo.all(Fortune)] + |> Enum.sort_by(& &1.message) - render(conn, :fortunes, - fortunes: Enum.sort(fortunes, fn f1, f2 -> f1.message < f2.message end) - ) + render(conn, :fortunes, fortunes: fortunes) end def updates(conn, params) do @@ -54,9 +55,13 @@ defmodule HelloWeb.PageController do worlds = Stream.repeatedly(&random_id/0) |> Stream.uniq() - |> Stream.map(fn idx -> Repo.get(World, idx) end) + |> Stream.map(&Repo.get(World, &1)) |> Stream.map(fn world -> %{id: world.id, randomnumber: :rand.uniform(@random_max)} end) |> Enum.take(size(params["queries"])) + # If this is not sorted it sometimes generates + # FAIL for http://tfb-server:8080/updates/20 + # Only 20470 executed queries in the database out of roughly 20480 expected. + |> Enum.sort_by(& &1.id) Repo.insert_all( World, @@ -75,28 +80,17 @@ defmodule HelloWeb.PageController do def cached(conn, params) do :rand.seed(:exsp) + WorldCache.seed() worlds = Stream.repeatedly(&random_id/0) |> Stream.uniq() - |> Stream.map(&get_cached_world/1) + |> Stream.map(&WorldCache.fetch(&1)) |> Enum.take(size(params["count"])) json(conn, worlds) end - defp get_cached_world(idx) do - case Cache.get(idx) do - nil -> - world = Repo.get(World, idx) - :ok = Cache.put(idx, world) - world - - world -> - world - end - end - defp random_id() do :rand.uniform(@random_max) end diff --git a/frameworks/Elixir/phoenix/lib/hello_web/controllers/page_html/fortunes.html.eex b/frameworks/Elixir/phoenix/lib/hello_web/controllers/page_html/fortunes.html.heex similarity index 100% rename from frameworks/Elixir/phoenix/lib/hello_web/controllers/page_html/fortunes.html.eex rename to frameworks/Elixir/phoenix/lib/hello_web/controllers/page_html/fortunes.html.heex diff --git a/frameworks/Elixir/phoenix/mix.exs b/frameworks/Elixir/phoenix/mix.exs index fa48c24784d..a0ecab89cd7 100755 --- a/frameworks/Elixir/phoenix/mix.exs +++ b/frameworks/Elixir/phoenix/mix.exs @@ -4,8 +4,8 @@ defmodule Hello.Mixfile do def project do [ app: :hello, - version: "0.1.0", - elixir: "~> 1.14", + version: "1.1.1", + elixir: "~> 1.17", elixirc_paths: elixirc_paths(Mix.env()), start_permanent: Mix.env() == :prod, deps: deps() @@ -29,17 +29,17 @@ defmodule Hello.Mixfile do # Type `mix help deps` for examples and options defp deps do [ - {:bandit, "~> 1.0.0-pre.5"}, + {:bandit, "~> 1.0.0"}, {:gettext, "~> 0.20"}, - {:ecto_sql, "~> 3.7"}, + {:ecto_sql, "~> 3.10"}, {:jason, "~> 1.2"}, {:phoenix, "~> 1.7"}, - {:phoenix_ecto, "~> 4.4"}, - {:phoenix_html, "~> 3.2"}, {:phoenix_live_view, "~> 0.18"}, + {:phoenix_ecto, "~> 4.4"}, + {:phoenix_html, "~> 4.1"}, {:plug_cowboy, "~> 2.5"}, - {:postgrex, "~> 0.15"}, - {:nebulex, "~> 2.4"} + {:postgrex, ">= 0.0.0"}, + {:nebulex, "~> 2.6"} ] end end diff --git a/frameworks/Elixir/phoenix/mix.lock b/frameworks/Elixir/phoenix/mix.lock index 415edcb0107..f3c8c288625 100644 --- a/frameworks/Elixir/phoenix/mix.lock +++ b/frameworks/Elixir/phoenix/mix.lock @@ -1,32 +1,32 @@ %{ - "bandit": {:hex, :bandit, "1.0.0-pre.5", "94b668f987a3b63f53123d2bdef1aaab73439eb02fcef7eb99032038206cab54", [:mix], [{:hpax, "~> 0.1.1", [hex: :hpax, repo: "hexpm", optional: false]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}, {:thousand_island, "~> 1.0-pre", [hex: :thousand_island, repo: "hexpm", optional: false]}, {:websock, "~> 0.5", [hex: :websock, repo: "hexpm", optional: false]}], "hexpm", "686da83f0c2cabd68cc221067ab43bc50af88c3e7fc8ef824a0b7039a978e383"}, - "castore": {:hex, :castore, "1.0.2", "0c6292ecf3e3f20b7c88408f00096337c4bfd99bd46cc2fe63413ddbe45b3573", [:mix], [], "hexpm", "40b2dd2836199203df8500e4a270f10fc006cc95adc8a319e148dc3077391d96"}, - "cowboy": {:hex, :cowboy, "2.10.0", "ff9ffeff91dae4ae270dd975642997afe2a1179d94b1887863e43f681a203e26", [:make, :rebar3], [{:cowlib, "2.12.1", [hex: :cowlib, repo: "hexpm", optional: false]}, {:ranch, "1.8.0", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm", "3afdccb7183cc6f143cb14d3cf51fa00e53db9ec80cdcd525482f5e99bc41d6b"}, + "bandit": {:hex, :bandit, "1.0.0", "2bd87bbf713d0eed0090f2fa162cd1676198122e6c2b68a201c706e354a6d5e5", [:mix], [{:hpax, "~> 0.1.1", [hex: :hpax, repo: "hexpm", optional: false]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}, {:thousand_island, "~> 1.0", [hex: :thousand_island, repo: "hexpm", optional: false]}, {:websock, "~> 0.5", [hex: :websock, repo: "hexpm", optional: false]}], "hexpm", "32acf6ac030fee1f99fd9c3fcf81671911ae8637e0a61c98111861b466efafdb"}, + "castore": {:hex, :castore, "1.0.8", "dedcf20ea746694647f883590b82d9e96014057aff1d44d03ec90f36a5c0dc6e", [:mix], [], "hexpm", "0b2b66d2ee742cb1d9cb8c8be3b43c3a70ee8651f37b75a8b982e036752983f1"}, + "cowboy": {:hex, :cowboy, "2.12.0", "f276d521a1ff88b2b9b4c54d0e753da6c66dd7be6c9fca3d9418b561828a3731", [:make, :rebar3], [{:cowlib, "2.13.0", [hex: :cowlib, repo: "hexpm", optional: false]}, {:ranch, "1.8.0", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm", "8a7abe6d183372ceb21caa2709bec928ab2b72e18a3911aa1771639bef82651e"}, "cowboy_telemetry": {:hex, :cowboy_telemetry, "0.4.0", "f239f68b588efa7707abce16a84d0d2acf3a0f50571f8bb7f56a15865aae820c", [:rebar3], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "7d98bac1ee4565d31b62d59f8823dfd8356a169e7fcbb83831b8a5397404c9de"}, - "cowlib": {:hex, :cowlib, "2.12.1", "a9fa9a625f1d2025fe6b462cb865881329b5caff8f1854d1cbc9f9533f00e1e1", [:make, :rebar3], [], "hexpm", "163b73f6367a7341b33c794c4e88e7dbfe6498ac42dcd69ef44c5bc5507c8db0"}, - "db_connection": {:hex, :db_connection, "2.5.0", "bb6d4f30d35ded97b29fe80d8bd6f928a1912ca1ff110831edcd238a1973652c", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "c92d5ba26cd69ead1ff7582dbb860adeedfff39774105a4f1c92cbb654b55aa2"}, + "cowlib": {:hex, :cowlib, "2.13.0", "db8f7505d8332d98ef50a3ef34b34c1afddec7506e4ee4dd4a3a266285d282ca", [:make, :rebar3], [], "hexpm", "e1e1284dc3fc030a64b1ad0d8382ae7e99da46c3246b815318a4b848873800a4"}, + "db_connection": {:hex, :db_connection, "2.7.0", "b99faa9291bb09892c7da373bb82cba59aefa9b36300f6145c5f201c7adf48ec", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "dcf08f31b2701f857dfc787fbad78223d61a32204f217f15e881dd93e4bdd3ff"}, "decimal": {:hex, :decimal, "2.1.1", "5611dca5d4b2c3dd497dec8f68751f1f1a54755e8ed2a966c2633cf885973ad6", [:mix], [], "hexpm", "53cfe5f497ed0e7771ae1a475575603d77425099ba5faef9394932b35020ffcc"}, - "ecto": {:hex, :ecto, "3.10.1", "c6757101880e90acc6125b095853176a02da8f1afe056f91f1f90b80c9389822", [:mix], [{:decimal, "~> 1.6 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "d2ac4255f1601bdf7ac74c0ed971102c6829dc158719b94bd30041bbad77f87a"}, - "ecto_sql": {:hex, :ecto_sql, "3.10.1", "6ea6b3036a0b0ca94c2a02613fd9f742614b5cfe494c41af2e6571bb034dd94c", [:mix], [{:db_connection, "~> 2.4.1 or ~> 2.5", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.10.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:myxql, "~> 0.6.0", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.16.0 or ~> 0.17.0 or ~> 1.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:tds, "~> 2.1.1 or ~> 2.2", [hex: :tds, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "f6a25bdbbd695f12c8171eaff0851fa4c8e72eec1e98c7364402dda9ce11c56b"}, - "expo": {:hex, :expo, "0.4.1", "1c61d18a5df197dfda38861673d392e642649a9cef7694d2f97a587b2cfb319b", [:mix], [], "hexpm", "2ff7ba7a798c8c543c12550fa0e2cbc81b95d4974c65855d8d15ba7b37a1ce47"}, - "gettext": {:hex, :gettext, "0.22.2", "6bfca374de34ecc913a28ba391ca184d88d77810a3e427afa8454a71a51341ac", [:mix], [{:expo, "~> 0.4.0", [hex: :expo, repo: "hexpm", optional: false]}], "hexpm", "8a2d389673aea82d7eae387e6a2ccc12660610080ae7beb19452cfdc1ec30f60"}, + "ecto": {:hex, :ecto, "3.11.2", "e1d26be989db350a633667c5cda9c3d115ae779b66da567c68c80cfb26a8c9ee", [:mix], [{:decimal, "~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "3c38bca2c6f8d8023f2145326cc8a80100c3ffe4dcbd9842ff867f7fc6156c65"}, + "ecto_sql": {:hex, :ecto_sql, "3.11.3", "4eb7348ff8101fbc4e6bbc5a4404a24fecbe73a3372d16569526b0cf34ebc195", [:mix], [{:db_connection, "~> 2.4.1 or ~> 2.5", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.11.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:myxql, "~> 0.6", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.16 or ~> 1.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:tds, "~> 2.1.1 or ~> 2.2", [hex: :tds, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "e5f36e3d736b99c7fee3e631333b8394ade4bafe9d96d35669fca2d81c2be928"}, + "expo": {:hex, :expo, "1.0.0", "647639267e088717232f4d4451526e7a9de31a3402af7fcbda09b27e9a10395a", [:mix], [], "hexpm", "18d2093d344d97678e8a331ca0391e85d29816f9664a25653fd7e6166827827c"}, + "gettext": {:hex, :gettext, "0.25.0", "98a95a862a94e2d55d24520dd79256a15c87ea75b49673a2e2f206e6ebc42e5d", [:mix], [{:expo, "~> 0.5.1 or ~> 1.0", [hex: :expo, repo: "hexpm", optional: false]}], "hexpm", "38e5d754e66af37980a94fb93bb20dcde1d2361f664b0a19f01e87296634051f"}, "hpax": {:hex, :hpax, "0.1.2", "09a75600d9d8bbd064cdd741f21fc06fc1f4cf3d0fcc335e5aa19be1a7235c84", [:mix], [], "hexpm", "2c87843d5a23f5f16748ebe77969880e29809580efdaccd615cd3bed628a8c13"}, - "jason": {:hex, :jason, "1.4.0", "e855647bc964a44e2f67df589ccf49105ae039d4179db7f6271dfd3843dc27e6", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "79a3791085b2a0f743ca04cec0f7be26443738779d09302e01318f97bdb82121"}, - "mime": {:hex, :mime, "2.0.5", "dc34c8efd439abe6ae0343edbb8556f4d63f178594894720607772a041b04b02", [:mix], [], "hexpm", "da0d64a365c45bc9935cc5c8a7fc5e49a0e0f9932a761c55d6c52b142780a05c"}, - "nebulex": {:hex, :nebulex, "2.5.1", "8ffbde30643e76d6cec712281ca68ab05f73170de9e758a39bc7e4e6987f608f", [:mix], [{:decorator, "~> 1.4", [hex: :decorator, repo: "hexpm", optional: true]}, {:shards, "~> 1.1", [hex: :shards, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: true]}], "hexpm", "8d0d3800d98c68ee19b229b7fe35fac0192ab5963a573612cf74a388e083bccf"}, - "phoenix": {:hex, :phoenix, "1.7.3", "4d8eca2c020c9ed81a28e7a8c60e0a4f6f9f7f6e12eb91dfd01301eac07424c1", [:mix], [{:castore, ">= 0.0.0", [hex: :castore, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 2.1", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:phoenix_template, "~> 1.0", [hex: :phoenix_template, repo: "hexpm", optional: false]}, {:phoenix_view, "~> 2.0", [hex: :phoenix_view, repo: "hexpm", optional: true]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.6", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:plug_crypto, "~> 1.2", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}, {:websock_adapter, "~> 0.4", [hex: :websock_adapter, repo: "hexpm", optional: false]}], "hexpm", "6b1bc308758f95ecf3e0d795389440a2ca88a903e0fda1f921c780918c16d640"}, - "phoenix_ecto": {:hex, :phoenix_ecto, "4.4.2", "b21bd01fdeffcfe2fab49e4942aa938b6d3e89e93a480d4aee58085560a0bc0d", [:mix], [{:ecto, "~> 3.5", [hex: :ecto, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.14.2 or ~> 3.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:plug, "~> 1.9", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "70242edd4601d50b69273b057ecf7b684644c19ee750989fd555625ae4ce8f5d"}, - "phoenix_html": {:hex, :phoenix_html, "3.3.1", "4788757e804a30baac6b3fc9695bf5562465dd3f1da8eb8460ad5b404d9a2178", [:mix], [{:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "bed1906edd4906a15fd7b412b85b05e521e1f67c9a85418c55999277e553d0d3"}, - "phoenix_live_view": {:hex, :phoenix_live_view, "0.19.0", "de5643d03e3cdf5ff19cd45b5d14543a3b1ad8551d529f6b24246e88a6c6f1b8", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix, "~> 1.6.15 or ~> 1.7.0", [hex: :phoenix, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 3.3", [hex: :phoenix_html, repo: "hexpm", optional: false]}, {:phoenix_template, "~> 1.0", [hex: :phoenix_template, repo: "hexpm", optional: false]}, {:phoenix_view, "~> 2.0", [hex: :phoenix_view, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.2 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "a650b6f814c4f386314b98f1aebf92f8652649166612f84ef2e60a20894addfa"}, - "phoenix_pubsub": {:hex, :phoenix_pubsub, "2.1.2", "a4950b63ace57720b0fc1c6da083c53346b36f99021de89595cc4f026288ff51", [:mix], [], "hexpm", "45741676a94c71f9afdfed9d22d49b6856c026ff504db04e3dc03a1d86f8201c"}, - "phoenix_template": {:hex, :phoenix_template, "1.0.1", "85f79e3ad1b0180abb43f9725973e3b8c2c3354a87245f91431eec60553ed3ef", [:mix], [{:phoenix_html, "~> 2.14.2 or ~> 3.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}], "hexpm", "157dc078f6226334c91cb32c1865bf3911686f8bcd6bcff86736f6253e6993ee"}, - "plug": {:hex, :plug, "1.14.2", "cff7d4ec45b4ae176a227acd94a7ab536d9b37b942c8e8fa6dfc0fff98ff4d80", [:mix], [{:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.1.1 or ~> 1.2", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.3 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "842fc50187e13cf4ac3b253d47d9474ed6c296a8732752835ce4a86acdf68d13"}, - "plug_cowboy": {:hex, :plug_cowboy, "2.6.1", "9a3bbfceeb65eff5f39dab529e5cd79137ac36e913c02067dba3963a26efe9b2", [:mix], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:cowboy_telemetry, "~> 0.3", [hex: :cowboy_telemetry, repo: "hexpm", optional: false]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "de36e1a21f451a18b790f37765db198075c25875c64834bcc82d90b309eb6613"}, - "plug_crypto": {:hex, :plug_crypto, "1.2.5", "918772575e48e81e455818229bf719d4ab4181fcbf7f85b68a35620f78d89ced", [:mix], [], "hexpm", "26549a1d6345e2172eb1c233866756ae44a9609bd33ee6f99147ab3fd87fd842"}, - "postgrex": {:hex, :postgrex, "0.17.1", "01c29fd1205940ee55f7addb8f1dc25618ca63a8817e56fac4f6846fc2cddcbe", [:mix], [{:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:table, "~> 0.1.0", [hex: :table, repo: "hexpm", optional: true]}], "hexpm", "14b057b488e73be2beee508fb1955d8db90d6485c6466428fe9ccf1d6692a555"}, + "jason": {:hex, :jason, "1.4.4", "b9226785a9aa77b6857ca22832cffa5d5011a667207eb2a0ad56adb5db443b8a", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "c5eb0cab91f094599f94d55bc63409236a8ec69a21a67814529e8d5f6cc90b3b"}, + "mime": {:hex, :mime, "2.0.6", "8f18486773d9b15f95f4f4f1e39b710045fa1de891fada4516559967276e4dc2", [:mix], [], "hexpm", "c9945363a6b26d747389aac3643f8e0e09d30499a138ad64fe8fd1d13d9b153e"}, + "nebulex": {:hex, :nebulex, "2.6.3", "78af348ed9f8a338871b41e0b6de718c1808e627ce03fbe86598cbda2bdda2f5", [:mix], [{:decorator, "~> 1.4", [hex: :decorator, repo: "hexpm", optional: true]}, {:shards, "~> 1.1", [hex: :shards, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: true]}], "hexpm", "09cdcbb62f8463ffcec7cae4936425ce91e25d92a6cd37e48b5dda7c851958d5"}, + "phoenix": {:hex, :phoenix, "1.7.14", "a7d0b3f1bc95987044ddada111e77bd7f75646a08518942c72a8440278ae7825", [:mix], [{:castore, ">= 0.0.0", [hex: :castore, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 2.1", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:phoenix_template, "~> 1.0", [hex: :phoenix_template, repo: "hexpm", optional: false]}, {:phoenix_view, "~> 2.0", [hex: :phoenix_view, repo: "hexpm", optional: true]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.7", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:plug_crypto, "~> 1.2 or ~> 2.0", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}, {:websock_adapter, "~> 0.5.3", [hex: :websock_adapter, repo: "hexpm", optional: false]}], "hexpm", "c7859bc56cc5dfef19ecfc240775dae358cbaa530231118a9e014df392ace61a"}, + "phoenix_ecto": {:hex, :phoenix_ecto, "4.6.2", "3b83b24ab5a2eb071a20372f740d7118767c272db386831b2e77638c4dcc606d", [:mix], [{:ecto, "~> 3.5", [hex: :ecto, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.14.2 or ~> 3.0 or ~> 4.1", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:plug, "~> 1.9", [hex: :plug, repo: "hexpm", optional: false]}, {:postgrex, "~> 0.16 or ~> 1.0", [hex: :postgrex, repo: "hexpm", optional: true]}], "hexpm", "3f94d025f59de86be00f5f8c5dd7b5965a3298458d21ab1c328488be3b5fcd59"}, + "phoenix_html": {:hex, :phoenix_html, "4.1.1", "4c064fd3873d12ebb1388425a8f2a19348cef56e7289e1998e2d2fa758aa982e", [:mix], [], "hexpm", "f2f2df5a72bc9a2f510b21497fd7d2b86d932ec0598f0210fed4114adc546c6f"}, + "phoenix_live_view": {:hex, :phoenix_live_view, "0.20.17", "f396bbdaf4ba227b82251eb75ac0afa6b3da5e509bc0d030206374237dfc9450", [:mix], [{:floki, "~> 0.36", [hex: :floki, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix, "~> 1.6.15 or ~> 1.7.0", [hex: :phoenix, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 3.3 or ~> 4.0", [hex: :phoenix_html, repo: "hexpm", optional: false]}, {:phoenix_template, "~> 1.0", [hex: :phoenix_template, repo: "hexpm", optional: false]}, {:phoenix_view, "~> 2.0", [hex: :phoenix_view, repo: "hexpm", optional: true]}, {:plug, "~> 1.15", [hex: :plug, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.2 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "a61d741ffb78c85fdbca0de084da6a48f8ceb5261a79165b5a0b59e5f65ce98b"}, + "phoenix_pubsub": {:hex, :phoenix_pubsub, "2.1.3", "3168d78ba41835aecad272d5e8cd51aa87a7ac9eb836eabc42f6e57538e3731d", [:mix], [], "hexpm", "bba06bc1dcfd8cb086759f0edc94a8ba2bc8896d5331a1e2c2902bf8e36ee502"}, + "phoenix_template": {:hex, :phoenix_template, "1.0.4", "e2092c132f3b5e5b2d49c96695342eb36d0ed514c5b252a77048d5969330d639", [:mix], [{:phoenix_html, "~> 2.14.2 or ~> 3.0 or ~> 4.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}], "hexpm", "2c0c81f0e5c6753faf5cca2f229c9709919aba34fab866d3bc05060c9c444206"}, + "plug": {:hex, :plug, "1.16.1", "40c74619c12f82736d2214557dedec2e9762029b2438d6d175c5074c933edc9d", [:mix], [{:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.1.1 or ~> 1.2 or ~> 2.0", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.3 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "a13ff6b9006b03d7e33874945b2755253841b238c34071ed85b0e86057f8cddc"}, + "plug_cowboy": {:hex, :plug_cowboy, "2.7.1", "87677ffe3b765bc96a89be7960f81703223fe2e21efa42c125fcd0127dd9d6b2", [:mix], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:cowboy_telemetry, "~> 0.3", [hex: :cowboy_telemetry, repo: "hexpm", optional: false]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "02dbd5f9ab571b864ae39418db7811618506256f6d13b4a45037e5fe78dc5de3"}, + "plug_crypto": {:hex, :plug_crypto, "2.1.0", "f44309c2b06d249c27c8d3f65cfe08158ade08418cf540fd4f72d4d6863abb7b", [:mix], [], "hexpm", "131216a4b030b8f8ce0f26038bc4421ae60e4bb95c5cf5395e1421437824c4fa"}, + "postgrex": {:hex, :postgrex, "0.19.0", "f7d50e50cb42e0a185f5b9a6095125a9ab7e4abccfbe2ab820ab9aa92b71dbab", [:mix], [{:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:table, "~> 0.1.0", [hex: :table, repo: "hexpm", optional: true]}], "hexpm", "dba2d2a0a8637defbf2307e8629cb2526388ba7348f67d04ec77a5d6a72ecfae"}, "ranch": {:hex, :ranch, "1.8.0", "8c7a100a139fd57f17327b6413e4167ac559fbc04ca7448e9be9057311597a1d", [:make, :rebar3], [], "hexpm", "49fbcfd3682fab1f5d109351b61257676da1a2fdbe295904176d5e521a2ddfe5"}, "telemetry": {:hex, :telemetry, "1.2.1", "68fdfe8d8f05a8428483a97d7aab2f268aaff24b49e0f599faa091f1d4e7f61c", [:rebar3], [], "hexpm", "dad9ce9d8effc621708f99eac538ef1cbe05d6a874dd741de2e689c47feafed5"}, - "thousand_island": {:hex, :thousand_island, "1.0.0-pre.3", "67b31809769736031b240339fa5096a6e491b7d7ec5e0e37ee80cab10e8712a9", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "75602046418b2510aac3c968b2941778187fe88256010116834903b806d77f53"}, - "websock": {:hex, :websock, "0.5.1", "c496036ce95bc26d08ba086b2a827b212c67e7cabaa1c06473cd26b40ed8cf10", [:mix], [], "hexpm", "b9f785108b81cd457b06e5f5dabe5f65453d86a99118b2c0a515e1e296dc2d2c"}, - "websock_adapter": {:hex, :websock_adapter, "0.5.1", "292e6c56724e3457e808e525af0e9bcfa088cc7b9c798218e78658c7f9b85066", [:mix], [{:bandit, ">= 0.6.0", [hex: :bandit, repo: "hexpm", optional: true]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.6", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:websock, "~> 0.5", [hex: :websock, repo: "hexpm", optional: false]}], "hexpm", "8e2e1544bfde5f9d0442f9cec2f5235398b224f75c9e06b60557debf64248ec1"}, + "thousand_island": {:hex, :thousand_island, "1.3.5", "6022b6338f1635b3d32406ff98d68b843ba73b3aa95cfc27154223244f3a6ca5", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "2be6954916fdfe4756af3239fb6b6d75d0b8063b5df03ba76fd8a4c87849e180"}, + "websock": {:hex, :websock, "0.5.3", "2f69a6ebe810328555b6fe5c831a851f485e303a7c8ce6c5f675abeb20ebdadc", [:mix], [], "hexpm", "6105453d7fac22c712ad66fab1d45abdf049868f253cf719b625151460b8b453"}, + "websock_adapter": {:hex, :websock_adapter, "0.5.6", "0437fe56e093fd4ac422de33bf8fc89f7bc1416a3f2d732d8b2c8fd54792fe60", [:mix], [{:bandit, ">= 0.6.0", [hex: :bandit, repo: "hexpm", optional: true]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.6", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:websock, "~> 0.5", [hex: :websock, repo: "hexpm", optional: false]}], "hexpm", "e04378d26b0af627817ae84c92083b7e97aca3121196679b73c73b99d0d133ea"}, } diff --git a/frameworks/Elixir/phoenix/phoenix-bandit.dockerfile b/frameworks/Elixir/phoenix/phoenix-bandit.dockerfile deleted file mode 100644 index 103350fc6db..00000000000 --- a/frameworks/Elixir/phoenix/phoenix-bandit.dockerfile +++ /dev/null @@ -1,39 +0,0 @@ -ARG ELIXIR="1.14.5" -ARG ERLANG="26.0" -ARG ALPINE="3.17.3" - -ARG BUILDER_IMAGE="hexpm/elixir:${ELIXIR}-erlang-${ERLANG}-alpine-${ALPINE}" -ARG RUNNER_IMAGE="alpine:${ALPINE}" - -FROM ${BUILDER_IMAGE} AS builder - -ARG MIX_ENV="bandit" - -RUN mix local.hex --force && \ - mix local.rebar --force - -COPY mix.exs mix.lock ./ -RUN mix deps.get --force --only prod - -COPY config ./config - -RUN mix deps.compile - -COPY priv ./priv -COPY lib ./lib - -COPY rel ./rel -RUN mix release --force --path /export - -# start a new build stage so that the final image will only contain -# the compiled release and other runtime necessities -FROM ${RUNNER_IMAGE} - -RUN apk add --no-cache libstdc++ openssl ncurses-libs - -COPY --from=builder /export /opt - -EXPOSE 8080 - -ENTRYPOINT ["/opt/bin/hello"] -CMD ["start"] diff --git a/frameworks/Elixir/phoenix/phoenix.dockerfile b/frameworks/Elixir/phoenix/phoenix.dockerfile index c9e0d7701b2..dcf8df3dd20 100644 --- a/frameworks/Elixir/phoenix/phoenix.dockerfile +++ b/frameworks/Elixir/phoenix/phoenix.dockerfile @@ -1,6 +1,6 @@ -ARG ELIXIR="1.14.5" -ARG ERLANG="26.0" -ARG ALPINE="3.17.3" +ARG ELIXIR="1.17.2" +ARG ERLANG="27.0.1" +ARG ALPINE="3.19.3" ARG BUILDER_IMAGE="hexpm/elixir:${ELIXIR}-erlang-${ERLANG}-alpine-${ALPINE}" ARG RUNNER_IMAGE="alpine:${ALPINE}" diff --git a/frameworks/Elixir/plug/elixir-plug-ecto.dockerfile b/frameworks/Elixir/plug/elixir-plug-ecto.dockerfile index a674dd80178..c943ba48991 100644 --- a/frameworks/Elixir/plug/elixir-plug-ecto.dockerfile +++ b/frameworks/Elixir/plug/elixir-plug-ecto.dockerfile @@ -1,6 +1,6 @@ -ARG ELIXIR="1.14.2" -ARG ERLANG="25.1.2" -ARG ALPINE="3.16.2" +ARG ELIXIR="1.17.2" +ARG ERLANG="27.0.1" +ARG ALPINE="3.19.3" ARG BUILDER_IMAGE="hexpm/elixir:${ELIXIR}-erlang-${ERLANG}-alpine-${ALPINE}" ARG RUNNER_IMAGE="alpine:${ALPINE}" diff --git a/frameworks/Elixir/plug/mix.exs b/frameworks/Elixir/plug/mix.exs index 1660a684b65..dcb29917a46 100644 --- a/frameworks/Elixir/plug/mix.exs +++ b/frameworks/Elixir/plug/mix.exs @@ -4,8 +4,8 @@ defmodule FrameworkBenchmarks.MixProject do def project do [ app: :framework_benchmarks, - version: "1.1.0", - elixir: "~> 1.14", + version: "1.1.1", + elixir: "~> 1.17", start_permanent: Mix.env() == :prod, deps: deps() ] @@ -24,10 +24,10 @@ defmodule FrameworkBenchmarks.MixProject do [ {:plug_cowboy, "~> 2.5"}, {:jason, "~> 1.4"}, - {:ecto_sql, "~> 3.8"}, - {:postgrex, "~> 0.16"}, - {:cachex, "~> 3.4"}, - {:phoenix_html, "~> 3.2"} + {:ecto_sql, "~> 3.10"}, + {:postgrex, ">= 0.0.0"}, + {:cachex, "~> 3.6"}, + {:phoenix_html, "~> 4.1"} ] end end diff --git a/frameworks/Elixir/plug/mix.lock b/frameworks/Elixir/plug/mix.lock index 324fedc25f8..fcc35f892b8 100644 --- a/frameworks/Elixir/plug/mix.lock +++ b/frameworks/Elixir/plug/mix.lock @@ -1,27 +1,23 @@ %{ "cachex": {:hex, :cachex, "3.6.0", "14a1bfbeee060dd9bec25a5b6f4e4691e3670ebda28c8ba2884b12fe30b36bf8", [:mix], [{:eternal, "~> 1.2", [hex: :eternal, repo: "hexpm", optional: false]}, {:jumper, "~> 1.0", [hex: :jumper, repo: "hexpm", optional: false]}, {:sleeplocks, "~> 1.1", [hex: :sleeplocks, repo: "hexpm", optional: false]}, {:unsafe, "~> 1.0", [hex: :unsafe, repo: "hexpm", optional: false]}], "hexpm", "ebf24e373883bc8e0c8d894a63bbe102ae13d918f790121f5cfe6e485cc8e2e2"}, - "connection": {:hex, :connection, "1.1.0", "ff2a49c4b75b6fb3e674bfc5536451607270aac754ffd1bdfe175abe4a6d7a68", [:mix], [], "hexpm", "722c1eb0a418fbe91ba7bd59a47e28008a189d47e37e0e7bb85585a016b2869c"}, - "cowboy": {:hex, :cowboy, "2.10.0", "ff9ffeff91dae4ae270dd975642997afe2a1179d94b1887863e43f681a203e26", [:make, :rebar3], [{:cowlib, "2.12.1", [hex: :cowlib, repo: "hexpm", optional: false]}, {:ranch, "1.8.0", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm", "3afdccb7183cc6f143cb14d3cf51fa00e53db9ec80cdcd525482f5e99bc41d6b"}, + "cowboy": {:hex, :cowboy, "2.12.0", "f276d521a1ff88b2b9b4c54d0e753da6c66dd7be6c9fca3d9418b561828a3731", [:make, :rebar3], [{:cowlib, "2.13.0", [hex: :cowlib, repo: "hexpm", optional: false]}, {:ranch, "1.8.0", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm", "8a7abe6d183372ceb21caa2709bec928ab2b72e18a3911aa1771639bef82651e"}, "cowboy_telemetry": {:hex, :cowboy_telemetry, "0.4.0", "f239f68b588efa7707abce16a84d0d2acf3a0f50571f8bb7f56a15865aae820c", [:rebar3], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "7d98bac1ee4565d31b62d59f8823dfd8356a169e7fcbb83831b8a5397404c9de"}, - "cowlib": {:hex, :cowlib, "2.12.1", "a9fa9a625f1d2025fe6b462cb865881329b5caff8f1854d1cbc9f9533f00e1e1", [:make, :rebar3], [], "hexpm", "163b73f6367a7341b33c794c4e88e7dbfe6498ac42dcd69ef44c5bc5507c8db0"}, - "db_connection": {:hex, :db_connection, "2.5.0", "bb6d4f30d35ded97b29fe80d8bd6f928a1912ca1ff110831edcd238a1973652c", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "c92d5ba26cd69ead1ff7582dbb860adeedfff39774105a4f1c92cbb654b55aa2"}, + "cowlib": {:hex, :cowlib, "2.13.0", "db8f7505d8332d98ef50a3ef34b34c1afddec7506e4ee4dd4a3a266285d282ca", [:make, :rebar3], [], "hexpm", "e1e1284dc3fc030a64b1ad0d8382ae7e99da46c3246b815318a4b848873800a4"}, + "db_connection": {:hex, :db_connection, "2.7.0", "b99faa9291bb09892c7da373bb82cba59aefa9b36300f6145c5f201c7adf48ec", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "dcf08f31b2701f857dfc787fbad78223d61a32204f217f15e881dd93e4bdd3ff"}, "decimal": {:hex, :decimal, "2.1.1", "5611dca5d4b2c3dd497dec8f68751f1f1a54755e8ed2a966c2633cf885973ad6", [:mix], [], "hexpm", "53cfe5f497ed0e7771ae1a475575603d77425099ba5faef9394932b35020ffcc"}, - "ecto": {:hex, :ecto, "3.10.1", "c6757101880e90acc6125b095853176a02da8f1afe056f91f1f90b80c9389822", [:mix], [{:decimal, "~> 1.6 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "d2ac4255f1601bdf7ac74c0ed971102c6829dc158719b94bd30041bbad77f87a"}, - "ecto_sql": {:hex, :ecto_sql, "3.10.1", "6ea6b3036a0b0ca94c2a02613fd9f742614b5cfe494c41af2e6571bb034dd94c", [:mix], [{:db_connection, "~> 2.4.1 or ~> 2.5", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.10.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:myxql, "~> 0.6.0", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.16.0 or ~> 0.17.0 or ~> 1.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:tds, "~> 2.1.1 or ~> 2.2", [hex: :tds, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "f6a25bdbbd695f12c8171eaff0851fa4c8e72eec1e98c7364402dda9ce11c56b"}, - "eljiffy": {:hex, :eljiffy, "1.3.0", "7e584be454c5ec3fc3ae472eedb4cb2185e9ed6cd863df383ef601de3f3b27fd", [:mix], [{:jiffy, "~> 1.0", [hex: :jiffy, repo: "hexpm", optional: false]}], "hexpm", "90420512d60fb45bc9c09221b4d89cc539c9bfefc1c62f24cb3e2cb13acf2215"}, + "ecto": {:hex, :ecto, "3.11.2", "e1d26be989db350a633667c5cda9c3d115ae779b66da567c68c80cfb26a8c9ee", [:mix], [{:decimal, "~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "3c38bca2c6f8d8023f2145326cc8a80100c3ffe4dcbd9842ff867f7fc6156c65"}, + "ecto_sql": {:hex, :ecto_sql, "3.11.3", "4eb7348ff8101fbc4e6bbc5a4404a24fecbe73a3372d16569526b0cf34ebc195", [:mix], [{:db_connection, "~> 2.4.1 or ~> 2.5", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.11.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:myxql, "~> 0.6", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.16 or ~> 1.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:tds, "~> 2.1.1 or ~> 2.2", [hex: :tds, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "e5f36e3d736b99c7fee3e631333b8394ade4bafe9d96d35669fca2d81c2be928"}, "eternal": {:hex, :eternal, "1.2.2", "d1641c86368de99375b98d183042dd6c2b234262b8d08dfd72b9eeaafc2a1abd", [:mix], [], "hexpm", "2c9fe32b9c3726703ba5e1d43a1d255a4f3f2d8f8f9bc19f094c7cb1a7a9e782"}, - "jason": {:hex, :jason, "1.4.0", "e855647bc964a44e2f67df589ccf49105ae039d4179db7f6271dfd3843dc27e6", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "79a3791085b2a0f743ca04cec0f7be26443738779d09302e01318f97bdb82121"}, - "jiffy": {:hex, :jiffy, "1.1.1", "aca10f47aa91697bf24ab9582c74e00e8e95474c7ef9f76d4f1a338d0f5de21b", [:rebar3], [], "hexpm", "62e1f0581c3c19c33a725c781dfa88410d8bff1bbafc3885a2552286b4785c4c"}, - "jumper": {:hex, :jumper, "1.0.1", "3c00542ef1a83532b72269fab9f0f0c82bf23a35e27d278bfd9ed0865cecabff", [:mix], [], "hexpm", "318c59078ac220e966d27af3646026db9b5a5e6703cb2aa3e26bcfaba65b7433"}, - "mime": {:hex, :mime, "2.0.5", "dc34c8efd439abe6ae0343edbb8556f4d63f178594894720607772a041b04b02", [:mix], [], "hexpm", "da0d64a365c45bc9935cc5c8a7fc5e49a0e0f9932a761c55d6c52b142780a05c"}, - "phoenix_html": {:hex, :phoenix_html, "3.3.1", "4788757e804a30baac6b3fc9695bf5562465dd3f1da8eb8460ad5b404d9a2178", [:mix], [{:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "bed1906edd4906a15fd7b412b85b05e521e1f67c9a85418c55999277e553d0d3"}, - "plug": {:hex, :plug, "1.14.2", "cff7d4ec45b4ae176a227acd94a7ab536d9b37b942c8e8fa6dfc0fff98ff4d80", [:mix], [{:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.1.1 or ~> 1.2", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.3 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "842fc50187e13cf4ac3b253d47d9474ed6c296a8732752835ce4a86acdf68d13"}, - "plug_cowboy": {:hex, :plug_cowboy, "2.6.1", "9a3bbfceeb65eff5f39dab529e5cd79137ac36e913c02067dba3963a26efe9b2", [:mix], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:cowboy_telemetry, "~> 0.3", [hex: :cowboy_telemetry, repo: "hexpm", optional: false]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "de36e1a21f451a18b790f37765db198075c25875c64834bcc82d90b309eb6613"}, - "plug_crypto": {:hex, :plug_crypto, "1.2.5", "918772575e48e81e455818229bf719d4ab4181fcbf7f85b68a35620f78d89ced", [:mix], [], "hexpm", "26549a1d6345e2172eb1c233866756ae44a9609bd33ee6f99147ab3fd87fd842"}, - "postgrex": {:hex, :postgrex, "0.17.1", "01c29fd1205940ee55f7addb8f1dc25618ca63a8817e56fac4f6846fc2cddcbe", [:mix], [{:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:table, "~> 0.1.0", [hex: :table, repo: "hexpm", optional: true]}], "hexpm", "14b057b488e73be2beee508fb1955d8db90d6485c6466428fe9ccf1d6692a555"}, + "jason": {:hex, :jason, "1.4.4", "b9226785a9aa77b6857ca22832cffa5d5011a667207eb2a0ad56adb5db443b8a", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "c5eb0cab91f094599f94d55bc63409236a8ec69a21a67814529e8d5f6cc90b3b"}, + "jumper": {:hex, :jumper, "1.0.2", "68cdcd84472a00ac596b4e6459a41b3062d4427cbd4f1e8c8793c5b54f1406a7", [:mix], [], "hexpm", "9b7782409021e01ab3c08270e26f36eb62976a38c1aa64b2eaf6348422f165e1"}, + "mime": {:hex, :mime, "2.0.6", "8f18486773d9b15f95f4f4f1e39b710045fa1de891fada4516559967276e4dc2", [:mix], [], "hexpm", "c9945363a6b26d747389aac3643f8e0e09d30499a138ad64fe8fd1d13d9b153e"}, + "phoenix_html": {:hex, :phoenix_html, "4.1.1", "4c064fd3873d12ebb1388425a8f2a19348cef56e7289e1998e2d2fa758aa982e", [:mix], [], "hexpm", "f2f2df5a72bc9a2f510b21497fd7d2b86d932ec0598f0210fed4114adc546c6f"}, + "plug": {:hex, :plug, "1.16.1", "40c74619c12f82736d2214557dedec2e9762029b2438d6d175c5074c933edc9d", [:mix], [{:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.1.1 or ~> 1.2 or ~> 2.0", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.3 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "a13ff6b9006b03d7e33874945b2755253841b238c34071ed85b0e86057f8cddc"}, + "plug_cowboy": {:hex, :plug_cowboy, "2.7.1", "87677ffe3b765bc96a89be7960f81703223fe2e21efa42c125fcd0127dd9d6b2", [:mix], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:cowboy_telemetry, "~> 0.3", [hex: :cowboy_telemetry, repo: "hexpm", optional: false]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "02dbd5f9ab571b864ae39418db7811618506256f6d13b4a45037e5fe78dc5de3"}, + "plug_crypto": {:hex, :plug_crypto, "2.1.0", "f44309c2b06d249c27c8d3f65cfe08158ade08418cf540fd4f72d4d6863abb7b", [:mix], [], "hexpm", "131216a4b030b8f8ce0f26038bc4421ae60e4bb95c5cf5395e1421437824c4fa"}, + "postgrex": {:hex, :postgrex, "0.19.0", "f7d50e50cb42e0a185f5b9a6095125a9ab7e4abccfbe2ab820ab9aa92b71dbab", [:mix], [{:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:table, "~> 0.1.0", [hex: :table, repo: "hexpm", optional: true]}], "hexpm", "dba2d2a0a8637defbf2307e8629cb2526388ba7348f67d04ec77a5d6a72ecfae"}, "ranch": {:hex, :ranch, "1.8.0", "8c7a100a139fd57f17327b6413e4167ac559fbc04ca7448e9be9057311597a1d", [:make, :rebar3], [], "hexpm", "49fbcfd3682fab1f5d109351b61257676da1a2fdbe295904176d5e521a2ddfe5"}, - "sleeplocks": {:hex, :sleeplocks, "1.1.2", "d45aa1c5513da48c888715e3381211c859af34bee9b8290490e10c90bb6ff0ca", [:rebar3], [], "hexpm", "9fe5d048c5b781d6305c1a3a0f40bb3dfc06f49bf40571f3d2d0c57eaa7f59a5"}, + "sleeplocks": {:hex, :sleeplocks, "1.1.3", "96a86460cc33b435c7310dbd27ec82ca2c1f24ae38e34f8edde97f756503441a", [:rebar3], [], "hexpm", "d3b3958552e6eb16f463921e70ae7c767519ef8f5be46d7696cc1ed649421321"}, "telemetry": {:hex, :telemetry, "1.2.1", "68fdfe8d8f05a8428483a97d7aab2f268aaff24b49e0f599faa091f1d4e7f61c", [:rebar3], [], "hexpm", "dad9ce9d8effc621708f99eac538ef1cbe05d6a874dd741de2e689c47feafed5"}, - "ucol": {:hex, :ucol, "2.0.0", "64f9589d682dac6ca59252e1222e22697784f74addd0b88c5e34d53d267356bb", [:rebar3], [], "hexpm", "b544b88ce034d1d1ab58e093744cbded9a1e8b05006870b4d3865d6cd5066a21"}, - "unsafe": {:hex, :unsafe, "1.0.1", "a27e1874f72ee49312e0a9ec2e0b27924214a05e3ddac90e91727bc76f8613d8", [:mix], [], "hexpm", "6c7729a2d214806450d29766abc2afaa7a2cbecf415be64f36a6691afebb50e5"}, + "unsafe": {:hex, :unsafe, "1.0.2", "23c6be12f6c1605364801f4b47007c0c159497d0446ad378b5cf05f1855c0581", [:mix], [], "hexpm", "b485231683c3ab01a9cd44cb4a79f152c6f3bb87358439c6f68791b85c2df675"}, } From 61ebc1487c02ebff63be9d467151f7b1b919775d Mon Sep 17 00:00:00 2001 From: Daniil Zotov <142039751+zoto-ff@users.noreply.github.com> Date: Wed, 14 Aug 2024 18:05:20 +0300 Subject: [PATCH 075/204] Update Bun (#9211) * update bun * use bun build --compile * kill children on parent exit --- frameworks/TypeScript/bun/bun.dockerfile | 8 +++++--- frameworks/TypeScript/bun/src/index.ts | 14 +++++++------- frameworks/TypeScript/bun/src/spawn.ts | 17 +++++++++++++---- 3 files changed, 25 insertions(+), 14 deletions(-) diff --git a/frameworks/TypeScript/bun/bun.dockerfile b/frameworks/TypeScript/bun/bun.dockerfile index 7692c8c82ae..ecf6ead2bbc 100644 --- a/frameworks/TypeScript/bun/bun.dockerfile +++ b/frameworks/TypeScript/bun/bun.dockerfile @@ -1,13 +1,15 @@ -FROM oven/bun:1.0 +FROM oven/bun:1.1 EXPOSE 8080 WORKDIR /app -USER bun - COPY ./src . ENV NODE_ENV=production +RUN bun build --compile --minify --outfile server . + +USER bun + CMD ["bun", "spawn.ts"] diff --git a/frameworks/TypeScript/bun/src/index.ts b/frameworks/TypeScript/bun/src/index.ts index be72a268363..45c0f303291 100644 --- a/frameworks/TypeScript/bun/src/index.ts +++ b/frameworks/TypeScript/bun/src/index.ts @@ -1,5 +1,5 @@ -const HELLO_WORLD_STR = "Hello, World!"; -const options: ResponseInit = { headers: { "Server": "Bun" } }; +const plainOptions: ResponseInit = { headers: { "Server": "Bun" } }; +const jsonOptions: ResponseInit = { headers: { "Server": "Bun", "Content-Type": "application/json" } }; const server = Bun.serve({ port: 8080, @@ -7,16 +7,16 @@ const server = Bun.serve({ fetch(req: Request) { const pathname = req.url.slice(req.url.indexOf("/", 8)); - if (pathname === "/json") { - return Response.json({ message: HELLO_WORLD_STR }, options); + if (pathname == "/json") { + return new Response(JSON.stringify({ message: "Hello, World!" }), jsonOptions); } - if (pathname === "/plaintext") { - return new Response(HELLO_WORLD_STR, options); + if (pathname == "/plaintext") { + return new Response("Hello, World!", plainOptions); } return new Response("", { status: 404 }) }, }); -console.log(`Listening on localhost:${server.port}`); +console.log(`Listening on ${server.url}\n`); diff --git a/frameworks/TypeScript/bun/src/spawn.ts b/frameworks/TypeScript/bun/src/spawn.ts index b3df7f03253..a6d990c1b67 100644 --- a/frameworks/TypeScript/bun/src/spawn.ts +++ b/frameworks/TypeScript/bun/src/spawn.ts @@ -1,9 +1,18 @@ -import os from "node:os"; +const cpus = navigator.hardwareConcurrency; +const buns = new Array(cpus); -const numCPUs = os.cpus().length; -for (let i = 0; i < numCPUs; i++) { - Bun.spawn(["bun", "index.ts"], { +for (let i = 0; i < cpus; i++) { + buns[i] = Bun.spawn(["./server"], { stdio: ["inherit", "inherit", "inherit"], env: { ...process.env }, }); } + +function kill() { + for (const bun of buns) { + bun.kill(); + } +} + +process.on("SIGINT", kill); +process.on("exit", kill); \ No newline at end of file From a3ff92743d6947417d589fdc1623e977698180a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9A=D0=BE=D1=81=D1=82=D1=8F=20=D0=A2=D1=80=D0=B5=D1=82?= =?UTF-8?q?=D1=8F=D0=BA?= Date: Wed, 14 Aug 2024 18:06:57 +0300 Subject: [PATCH 076/204] feat(ditsmod): upgrade npm packages and added bun integration. (#9213) --- .../TypeScript/ditsmod/benchmark_config.json | 132 ++++++++++++++++++ frameworks/TypeScript/ditsmod/bun.lockb | Bin 0 -> 59387 bytes .../ditsmod/ditsmod-bun-mysql.dockerfile | 17 +++ .../ditsmod/ditsmod-bun-postgres.dockerfile | 17 +++ .../TypeScript/ditsmod/ditsmod-bun.dockerfile | 12 ++ .../ditsmod/ditsmod-mysql.dockerfile | 2 +- .../ditsmod/ditsmod-postgres.dockerfile | 2 +- .../TypeScript/ditsmod/ditsmod.dockerfile | 2 +- frameworks/TypeScript/ditsmod/package.json | 11 +- .../TypeScript/ditsmod/src/app/app.module.ts | 9 +- .../app/bun-integration/bun-application.ts | 17 +++ .../src/app/bun-integration/bun-providers.ts | 21 +++ .../src/app/bun-integration/node-res.ts | 61 ++++++++ .../src/app/bun-integration/pre-router.ts | 26 ++++ .../ditsmod/src/app/bun-integration/spawn.ts | 9 ++ frameworks/TypeScript/ditsmod/src/main.bun.ts | 12 ++ frameworks/TypeScript/ditsmod/tsconfig.json | 15 +- 17 files changed, 349 insertions(+), 16 deletions(-) create mode 100755 frameworks/TypeScript/ditsmod/bun.lockb create mode 100644 frameworks/TypeScript/ditsmod/ditsmod-bun-mysql.dockerfile create mode 100644 frameworks/TypeScript/ditsmod/ditsmod-bun-postgres.dockerfile create mode 100644 frameworks/TypeScript/ditsmod/ditsmod-bun.dockerfile create mode 100644 frameworks/TypeScript/ditsmod/src/app/bun-integration/bun-application.ts create mode 100644 frameworks/TypeScript/ditsmod/src/app/bun-integration/bun-providers.ts create mode 100644 frameworks/TypeScript/ditsmod/src/app/bun-integration/node-res.ts create mode 100644 frameworks/TypeScript/ditsmod/src/app/bun-integration/pre-router.ts create mode 100644 frameworks/TypeScript/ditsmod/src/app/bun-integration/spawn.ts create mode 100644 frameworks/TypeScript/ditsmod/src/main.bun.ts diff --git a/frameworks/TypeScript/ditsmod/benchmark_config.json b/frameworks/TypeScript/ditsmod/benchmark_config.json index 42122a11d69..c16c9419bde 100755 --- a/frameworks/TypeScript/ditsmod/benchmark_config.json +++ b/frameworks/TypeScript/ditsmod/benchmark_config.json @@ -130,6 +130,138 @@ "display_name": "ditsmod [mysql & simplified use of di]", "notes": "Simplified use of Dependency Injection (no request level injector).", "versus": "nodejs" + }, + "bun": { + "dockerfile": "ditsmod-bun.dockerfile", + "json_url": "/json", + "plaintext_url": "/plaintext", + "port": 8080, + "approach": "Realistic", + "classification": "Micro", + "database": "None", + "framework": "Ditsmod", + "language": "TypeScript", + "flavor": "None", + "orm": "None", + "platform": "bun", + "webserver": "None", + "os": "Linux", + "database_os": "Linux", + "display_name": "Ditsmod on bun", + "notes": "", + "versus": "bun" + }, + "simplified-di-bun": { + "dockerfile": "ditsmod-bun.dockerfile", + "json_url": "/json2", + "plaintext_url": "/plaintext2", + "port": 8080, + "approach": "Realistic", + "classification": "Micro", + "database": "None", + "framework": "Ditsmod", + "language": "TypeScript", + "flavor": "None", + "orm": "None", + "platform": "bun", + "webserver": "None", + "os": "Linux", + "database_os": "Linux", + "display_name": "ditsmod on bun [simplified use of di]", + "notes": "Simplified use of Dependency Injection (no request level injector).", + "versus": "bun" + }, + "postgres-bun": { + "dockerfile": "ditsmod-bun-postgres.dockerfile", + "db_url": "/db", + "query_url": "/queries?queries=", + "update_url": "/updates?queries=", + "cached_query_url": "/cached-queries?count=", + "fortune_url": "/fortunes", + "port": 8080, + "approach": "Realistic", + "classification": "Micro", + "database": "Postgres", + "framework": "Ditsmod", + "language": "TypeScript", + "flavor": "None", + "orm": "Raw", + "platform": "bun", + "webserver": "None", + "os": "Linux", + "database_os": "Linux", + "display_name": "ditsmod on bun [postgres]", + "notes": "", + "versus": "bun" + }, + "mysql-bun": { + "dockerfile": "ditsmod-bun-mysql.dockerfile", + "db_url": "/db", + "query_url": "/queries?queries=", + "update_url": "/updates?queries=", + "cached_query_url": "/cached-queries?count=", + "fortune_url": "/fortunes", + "port": 8080, + "approach": "Realistic", + "classification": "Micro", + "database": "MySQL", + "framework": "Ditsmod", + "language": "TypeScript", + "flavor": "None", + "orm": "Raw", + "platform": "bun", + "webserver": "None", + "os": "Linux", + "database_os": "Linux", + "display_name": "ditsmod on bun [mysql]", + "notes": "", + "versus": "bun" + }, + "postgres2-bun": { + "dockerfile": "ditsmod-bun-postgres.dockerfile", + "db_url": "/db2", + "query_url": "/queries2?queries=", + "update_url": "/updates2?queries=", + "cached_query_url": "/cached-queries2?count=", + "fortune_url": "/fortunes2", + "port": 8080, + "approach": "Realistic", + "classification": "Micro", + "database": "Postgres", + "framework": "Ditsmod", + "language": "TypeScript", + "flavor": "None", + "orm": "Raw", + "platform": "bun", + "webserver": "None", + "os": "Linux", + "database_os": "Linux", + "display_name": "ditsmod on bun [postgres & simplified use of di]", + "notes": "Simplified use of Dependency Injection (no request level injector).", + "versus": "bun" + }, + "mysql2-bun": { + "dockerfile": "ditsmod-bun-mysql.dockerfile", + "db_url": "/db2", + "query_url": "/queries2?queries=", + "update_url": "/updates2?queries=", + "cached_query_url": "/cached-queries2?count=", + "fortune_url": "/fortunes2", + "port": 8080, + "approach": "Realistic", + "classification": "Micro", + "database": "MySQL", + "framework": "Ditsmod", + "language": "TypeScript", + "flavor": "None", + "orm": "Raw", + "platform": "bun", + "webserver": "None", + "os": "Linux", + "database_os": "Linux", + "display_name": "ditsmod on bun [mysql & simplified use of di]", + "notes": "Simplified use of Dependency Injection (no request level injector).", + "versus": "bun" } } ] diff --git a/frameworks/TypeScript/ditsmod/bun.lockb b/frameworks/TypeScript/ditsmod/bun.lockb new file mode 100755 index 0000000000000000000000000000000000000000..c15ebbf0d57fa7a70302adedf5ceb815a5c211fa GIT binary patch literal 59387 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 literal 0 HcmV?d00001 diff --git a/frameworks/TypeScript/ditsmod/ditsmod-bun-mysql.dockerfile b/frameworks/TypeScript/ditsmod/ditsmod-bun-mysql.dockerfile new file mode 100644 index 00000000000..c6c56b41443 --- /dev/null +++ b/frameworks/TypeScript/ditsmod/ditsmod-bun-mysql.dockerfile @@ -0,0 +1,17 @@ +FROM oven/bun:1.1 + +COPY ./ ./ + +RUN bun install +RUN bun run build + +ENV NODE_ENV production +ENV IS_BUN true +ENV DATABASE mysql +ENV MYSQL_HOST tfb-database +ENV MYSQL_USER benchmarkdbuser +ENV MYSQL_PSWD benchmarkdbpass +ENV MYSQL_DBNAME hello_world + +EXPOSE 8080 +CMD rm node_modules/@ditsmod/*/tsconfig.json && bun src/app/bun-integration/spawn.ts diff --git a/frameworks/TypeScript/ditsmod/ditsmod-bun-postgres.dockerfile b/frameworks/TypeScript/ditsmod/ditsmod-bun-postgres.dockerfile new file mode 100644 index 00000000000..6d10f0bfc7b --- /dev/null +++ b/frameworks/TypeScript/ditsmod/ditsmod-bun-postgres.dockerfile @@ -0,0 +1,17 @@ +FROM oven/bun:1.1 + +COPY ./ ./ + +RUN bun install +RUN bun run build + +ENV NODE_ENV production +ENV IS_BUN true +ENV DATABASE postgres +ENV PG_HOST tfb-database +ENV PG_USER benchmarkdbuser +ENV PG_PSWD benchmarkdbpass +ENV PG_DBNAME hello_world + +EXPOSE 8080 +CMD rm node_modules/@ditsmod/*/tsconfig.json && bun src/app/bun-integration/spawn.ts diff --git a/frameworks/TypeScript/ditsmod/ditsmod-bun.dockerfile b/frameworks/TypeScript/ditsmod/ditsmod-bun.dockerfile new file mode 100644 index 00000000000..d18c49cab44 --- /dev/null +++ b/frameworks/TypeScript/ditsmod/ditsmod-bun.dockerfile @@ -0,0 +1,12 @@ +FROM oven/bun:1.1 + +COPY ./ ./ + +RUN bun install +RUN bun run build + +ENV NODE_ENV production +ENV IS_BUN true + +EXPOSE 8080 +CMD rm node_modules/@ditsmod/*/tsconfig.json && bun src/app/bun-integration/spawn.ts diff --git a/frameworks/TypeScript/ditsmod/ditsmod-mysql.dockerfile b/frameworks/TypeScript/ditsmod/ditsmod-mysql.dockerfile index 4136e2ae860..95ad40e9ac8 100644 --- a/frameworks/TypeScript/ditsmod/ditsmod-mysql.dockerfile +++ b/frameworks/TypeScript/ditsmod/ditsmod-mysql.dockerfile @@ -1,4 +1,4 @@ -FROM node:18.17.1-slim +FROM node:20.16-slim COPY ./ ./ diff --git a/frameworks/TypeScript/ditsmod/ditsmod-postgres.dockerfile b/frameworks/TypeScript/ditsmod/ditsmod-postgres.dockerfile index 5ef79595757..89ecc3e80a8 100644 --- a/frameworks/TypeScript/ditsmod/ditsmod-postgres.dockerfile +++ b/frameworks/TypeScript/ditsmod/ditsmod-postgres.dockerfile @@ -1,4 +1,4 @@ -FROM node:18.17.1-slim +FROM node:20.16-slim COPY ./ ./ diff --git a/frameworks/TypeScript/ditsmod/ditsmod.dockerfile b/frameworks/TypeScript/ditsmod/ditsmod.dockerfile index 882239148ce..0b21155188a 100644 --- a/frameworks/TypeScript/ditsmod/ditsmod.dockerfile +++ b/frameworks/TypeScript/ditsmod/ditsmod.dockerfile @@ -1,4 +1,4 @@ -FROM node:18.17.1-slim +FROM node:20.16-slim COPY ./ ./ diff --git a/frameworks/TypeScript/ditsmod/package.json b/frameworks/TypeScript/ditsmod/package.json index 962d11cc65f..3d74a7822de 100755 --- a/frameworks/TypeScript/ditsmod/package.json +++ b/frameworks/TypeScript/ditsmod/package.json @@ -19,18 +19,19 @@ "author": "Костя Третяк", "license": "MIT", "dependencies": { - "@ditsmod/core": "~2.51.1", - "@ditsmod/routing": "~2.1.0", + "@ditsmod/core": "~2.54.2", + "@ditsmod/routing": "~2.3.0", "handlebars": "^4.7.8", - "lru-cache": "^10.0.1", - "mariadb": "^3.2.1", - "postgres": "^3.3.5" + "lru-cache": "^11.0.0", + "mariadb": "^3.3.1", + "postgres": "^3.4.4" }, "devDependencies": { "@types/eslint": "^8.44.2", "@types/node": "^20.5.7", "@typescript-eslint/eslint-plugin": "^6.5.0", "@typescript-eslint/parser": "^6.5.0", + "bun-types": "^1.1.22", "eslint": "^8.48.0", "prettier": "^3.0.2", "typescript": "^5.2.2" diff --git a/frameworks/TypeScript/ditsmod/src/app/app.module.ts b/frameworks/TypeScript/ditsmod/src/app/app.module.ts index 4874719f9cc..e0c1dfedcec 100644 --- a/frameworks/TypeScript/ditsmod/src/app/app.module.ts +++ b/frameworks/TypeScript/ditsmod/src/app/app.module.ts @@ -1,8 +1,13 @@ -import { Providers, rootModule } from '@ditsmod/core'; +import { PreRouter, rootModule } from '@ditsmod/core'; + import { SimpleModule } from '#routed/simple/simple.module.js'; +import { BunPreRouter } from './bun-integration/pre-router.js'; +import { BunProviders } from './bun-integration/bun-providers.js'; @rootModule({ appends: [SimpleModule], - providersPerApp: [...new Providers().useLogConfig({ level: 'off' })], + providersPerApp: [ + ...new BunProviders().useLogConfig({ level: 'off' }).if(process.env.IS_BUN).useClass(PreRouter, BunPreRouter), + ], }) export class AppModule {} diff --git a/frameworks/TypeScript/ditsmod/src/app/bun-integration/bun-application.ts b/frameworks/TypeScript/ditsmod/src/app/bun-integration/bun-application.ts new file mode 100644 index 00000000000..0b462db87bb --- /dev/null +++ b/frameworks/TypeScript/ditsmod/src/app/bun-integration/bun-application.ts @@ -0,0 +1,17 @@ +import { AnyFn, AppInitializer, Application } from '@ditsmod/core'; +import { Serve, Server } from 'bun'; + +export class BunApplication extends Application { + protected override createServer(requestListener: any): any { + const serveOptions = this.appOptions.serverOptions as Serve; + serveOptions.fetch ??= (req) => requestListener(req); + return Bun.serve(serveOptions); + } + + protected override async createServerAndBindToListening(appInitializer: AppInitializer, resolve: AnyFn) { + this.flushLogs(); + const server = (await this.createServer(appInitializer.requestListener)) as Server; + this.systemLogMediator.serverListen(this, server.hostname, server.port); + resolve({ server }); + } +} diff --git a/frameworks/TypeScript/ditsmod/src/app/bun-integration/bun-providers.ts b/frameworks/TypeScript/ditsmod/src/app/bun-integration/bun-providers.ts new file mode 100644 index 00000000000..0581973f421 --- /dev/null +++ b/frameworks/TypeScript/ditsmod/src/app/bun-integration/bun-providers.ts @@ -0,0 +1,21 @@ +import { Providers, Class } from '@ditsmod/core'; + +export class BunProviders extends Providers { + protected setCondition?: boolean; + protected ifCondition?: boolean; + + if(condition: any) { + this.setCondition = true; + this.ifCondition = condition; + return this; + } + + override useClass(token: A, useClass: B, multi?: boolean): this { + if (!this.setCondition || this.ifCondition) { + this.pushProvider({ token, useClass }, multi); + } + this.setCondition = undefined; + this.ifCondition = undefined; + return this; + } +} diff --git a/frameworks/TypeScript/ditsmod/src/app/bun-integration/node-res.ts b/frameworks/TypeScript/ditsmod/src/app/bun-integration/node-res.ts new file mode 100644 index 00000000000..7dae8de27a6 --- /dev/null +++ b/frameworks/TypeScript/ditsmod/src/app/bun-integration/node-res.ts @@ -0,0 +1,61 @@ +import { Writable } from 'node:stream'; + +export class NodeRes extends Writable { + #chunks: Buffer[] = []; + #resolve: (body: string) => void; + status: number = 200; + headers = {} as HeadersInit; + body = new Promise((resolve) => (this.#resolve = resolve)); + headersSent?: boolean; + statusText?: string; + + set statusCode(statusCode: number) { + this.status = statusCode; + } + + getHeader(name: string) { + return this.headers[name as keyof HeadersInit]; + } + + getHeaders() { + return this.headers; + } + + setHeader(name: string, value: number | string | readonly string[]) { + this.headers = { ...this.headers, [name]: value } as HeadersInit; + return this; + } + + writeHead(statusCode: number, headers?: HeadersInit): this; + writeHead(statusCode: number, statusMessage: string, headers?: HeadersInit): this; + writeHead(statusCode: number, statusMsgOrHeaders?: string | HeadersInit, headers?: HeadersInit): this { + this.status = statusCode; + if (typeof statusMsgOrHeaders == 'object') { + this.mergeHeaders(statusMsgOrHeaders); + } else { + this.statusText = statusMsgOrHeaders; + this.mergeHeaders(headers); + } + return this; + } + + override _write(chunk: any, encoding: BufferEncoding, callback: (error?: Error | null) => void): void { + this.#chunks.push(Buffer.from(chunk)); + callback(); + } + + override _final(callback: (error?: Error | null) => void): void { + const finalData = Buffer.concat(this.#chunks); + this.headersSent = true; + this.#resolve(finalData.toString()); + callback(); + } + + protected mergeHeaders(headers: HeadersInit = {}) { + if (Array.isArray(headers)) { + headers.forEach(([key, val]) => ((this.headers as any)[key] = val)); + } else { + this.headers = { ...this.headers, ...headers }; + } + } +} diff --git a/frameworks/TypeScript/ditsmod/src/app/bun-integration/pre-router.ts b/frameworks/TypeScript/ditsmod/src/app/bun-integration/pre-router.ts new file mode 100644 index 00000000000..26a0100e4e0 --- /dev/null +++ b/frameworks/TypeScript/ditsmod/src/app/bun-integration/pre-router.ts @@ -0,0 +1,26 @@ +import { PreRouter } from '@ditsmod/core'; +import { NodeRes } from './node-res.js'; + +export class BunPreRouter extends PreRouter { + override requestListener: any = async (req: Request) => { + const nodeReq = req as any; + const nodeRes = new NodeRes(); + + const url = new URL(req.url); + const uri = url.pathname; + const queryString = url.search.slice(1); + const { handle, params } = this.router.find(req.method as any, uri); + if (!handle) { + this.sendNotImplemented(nodeRes as any); + const body = await nodeRes.body; + return new Response(body, nodeRes); + } + + await handle(nodeReq, nodeRes as any, params!, queryString).catch((err) => { + this.sendInternalServerError(nodeRes as any, err); + }); + + const body = await nodeRes.body; + return new Response(body, nodeRes); + }; +} diff --git a/frameworks/TypeScript/ditsmod/src/app/bun-integration/spawn.ts b/frameworks/TypeScript/ditsmod/src/app/bun-integration/spawn.ts new file mode 100644 index 00000000000..439451029a4 --- /dev/null +++ b/frameworks/TypeScript/ditsmod/src/app/bun-integration/spawn.ts @@ -0,0 +1,9 @@ +import os from 'node:os'; + +const numCPUs = os.cpus().length; +for (let i = 0; i < numCPUs; i++) { + Bun.spawn(['bun', 'dist/main.bun.js'], { + stdio: ['inherit', 'inherit', 'inherit'], + env: { ...process.env }, + }); +} diff --git a/frameworks/TypeScript/ditsmod/src/main.bun.ts b/frameworks/TypeScript/ditsmod/src/main.bun.ts new file mode 100644 index 00000000000..42c0798a066 --- /dev/null +++ b/frameworks/TypeScript/ditsmod/src/main.bun.ts @@ -0,0 +1,12 @@ +import { Serve, Server } from 'bun'; + +import { AppModule } from './app/app.module.js'; +import { BunApplication } from './app/bun-integration/bun-application.js'; + +const reusePort = process.env.NODE_ENV == 'production'; +const serverOptions = { port: 8080, hostname: '0.0.0.0', reusePort } as Serve; +const { server } = await new BunApplication().bootstrap(AppModule, { + serverOptions: serverOptions as any, +}); + +const bunServer = server as unknown as Server; diff --git a/frameworks/TypeScript/ditsmod/tsconfig.json b/frameworks/TypeScript/ditsmod/tsconfig.json index 27c048aa781..ef1b58e6cb3 100644 --- a/frameworks/TypeScript/ditsmod/tsconfig.json +++ b/frameworks/TypeScript/ditsmod/tsconfig.json @@ -16,14 +16,17 @@ "noImplicitAny": true, "strictPropertyInitialization": false, "allowJs": false, - "paths": { - "#routed/*": ["./src/app/modules/routed/*"], - "#service/*": ["./src/app/modules/service/*"], - "#utils/*": ["./src/app/utils/*"], - } + "types": ["bun-types"], + // Bun works with bugs if this code is uncommented. + // "paths": { + // "#routed/*": ["./src/app/modules/routed/*"], + // "#service/*": ["./src/app/modules/service/*"], + // "#utils/*": ["./src/app/utils/*"], + // } }, "include": [ "src", - "test" + "test", + "./spawn.ts" ] } From b976fe8bccb062d06819a6f59440c6427e4d6859 Mon Sep 17 00:00:00 2001 From: Daniil Zotov <142039751+zoto-ff@users.noreply.github.com> Date: Wed, 14 Aug 2024 18:35:52 +0300 Subject: [PATCH 077/204] Update Elysia (#9212) * fix spawn.ts, update bun * update elysia, refactor /json and /plaintext * refactor db handlers * use bun build --compile --- frameworks/TypeScript/elysia/bun.lockb | Bin 4971 -> 4963 bytes .../elysia/elysia-postgres.dockerfile | 2 +- .../elysia/elysia-smol-postgres.dockerfile | 2 +- .../TypeScript/elysia/elysia.dockerfile | 2 +- frameworks/TypeScript/elysia/package.json | 11 +- frameworks/TypeScript/elysia/spawn.ts | 18 ++- .../TypeScript/elysia/src/db-handlers.ts | 118 +++++++++--------- frameworks/TypeScript/elysia/src/index.ts | 22 ++-- frameworks/TypeScript/elysia/src/postgres.ts | 12 +- frameworks/TypeScript/elysia/src/types.ts | 16 +-- 10 files changed, 105 insertions(+), 98 deletions(-) diff --git a/frameworks/TypeScript/elysia/bun.lockb b/frameworks/TypeScript/elysia/bun.lockb index a5f94fd2531601ff54fa87839a0663d66f7b3a7e..7e29924798c25d30517bcca2ed92c9934b0540fa 100755 GIT binary patch literal 4963 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 O9!-X(v7P6q@bBNZz1cbd diff --git a/frameworks/TypeScript/elysia/elysia-postgres.dockerfile b/frameworks/TypeScript/elysia/elysia-postgres.dockerfile index e3fda732c79..40ff868c528 100644 --- a/frameworks/TypeScript/elysia/elysia-postgres.dockerfile +++ b/frameworks/TypeScript/elysia/elysia-postgres.dockerfile @@ -1,4 +1,4 @@ -FROM oven/bun:1.0 +FROM oven/bun:1.1 EXPOSE 8080 diff --git a/frameworks/TypeScript/elysia/elysia-smol-postgres.dockerfile b/frameworks/TypeScript/elysia/elysia-smol-postgres.dockerfile index c222841c81a..de7b9d63bb0 100644 --- a/frameworks/TypeScript/elysia/elysia-smol-postgres.dockerfile +++ b/frameworks/TypeScript/elysia/elysia-smol-postgres.dockerfile @@ -1,4 +1,4 @@ -FROM oven/bun:1.0 +FROM oven/bun:1.1 EXPOSE 8080 diff --git a/frameworks/TypeScript/elysia/elysia.dockerfile b/frameworks/TypeScript/elysia/elysia.dockerfile index c05d3f41878..3ed07652df1 100644 --- a/frameworks/TypeScript/elysia/elysia.dockerfile +++ b/frameworks/TypeScript/elysia/elysia.dockerfile @@ -1,4 +1,4 @@ -FROM oven/bun:1.0 +FROM oven/bun:1.1 EXPOSE 8080 diff --git a/frameworks/TypeScript/elysia/package.json b/frameworks/TypeScript/elysia/package.json index 082042b5f55..ba38bf05ee6 100644 --- a/frameworks/TypeScript/elysia/package.json +++ b/frameworks/TypeScript/elysia/package.json @@ -3,15 +3,16 @@ "version": "0.0.1", "module": "src/index.js", "devDependencies": { - "bun-types": "latest" + "bun-types": "^1.1.23", + "typescript": "^5.5.4" }, "scripts": { "dev": "bun run --watch src/index.ts", "start": "bun run src/index.ts", - "build": "bun build --target=bun --minify src/index.ts --outdir=build" + "build": "bun build --compile --minify --outfile server src/index.ts" }, "dependencies": { - "elysia": "^0.7.17", - "postgres": "^3.4.1" + "elysia": "^1.1.6", + "postgres": "^3.4.4" } -} +} \ No newline at end of file diff --git a/frameworks/TypeScript/elysia/spawn.ts b/frameworks/TypeScript/elysia/spawn.ts index ae02e7169a7..3bf8959c230 100644 --- a/frameworks/TypeScript/elysia/spawn.ts +++ b/frameworks/TypeScript/elysia/spawn.ts @@ -1,10 +1,18 @@ -import os from 'node:os'; +const cpus = navigator.hardwareConcurrency; +const buns = new Array(cpus); -// @ts-ignore -const numCPUs = os.availableParallelism(); -for (let i = 0; i < numCPUs; i++) { - Bun.spawn(['bun', 'build/index.js'], { +for (let i = 0; i < cpus; i++) { + buns[i] = Bun.spawn(['./server'], { stdio: ['inherit', 'inherit', 'inherit'], env: { ...process.env }, }); } + +function kill() { + for (const bun of buns) { + bun.kill(); + } +} + +process.on('SIGINT', kill); +process.on('exit', kill); \ No newline at end of file diff --git a/frameworks/TypeScript/elysia/src/db-handlers.ts b/frameworks/TypeScript/elysia/src/db-handlers.ts index 0e099d6d8b6..d75e91ff1a5 100644 --- a/frameworks/TypeScript/elysia/src/db-handlers.ts +++ b/frameworks/TypeScript/elysia/src/db-handlers.ts @@ -1,83 +1,77 @@ import Elysia from 'elysia'; -import * as postgres from './postgres'; -import { Fortune, World } from './types'; +import * as db from './postgres'; +import { Fortune } from './types'; -const deps = new Elysia({ - name: 'deps', -}) - .decorate('db', postgres) - .decorate('generateRandomNumber', () => Math.ceil(Math.random() * 10000)) - .decorate('html', (fortunes: Fortune[]) => { - const n = fortunes.length; - - let html = ''; - for (let i = 0; i < n; i++) { - html += `${fortunes[i].id}${Bun.escapeHTML( - fortunes[i].message - )}`; - } +function rand () { + return Math.ceil(Math.random() * 10000) +} - return `Fortunes${html}
idmessage
`; - }); +function parseQueriesNumber (q?: string) { + return Math.min(parseInt(q || '1') || 1, 500) +} + +function renderTemplate (fortunes: Fortune[]) { + const n = fortunes.length; + + let html = ''; + for (let i = 0; i < n; i++) { + html += `${fortunes[i].id}${Bun.escapeHTML( + fortunes[i].message + )}`; + } + + return `Fortunes${html}
idmessage
`; +} const dbHandlers = new Elysia({ name: 'db-handlers', }) - .use(deps) - .get( - '/db', - async ({ db, generateRandomNumber }) => - await db.find(generateRandomNumber()) - ) - .get( - '/fortunes', - async ({ db, html }) => { - const fortunes = await db.fortunes(); - - fortunes.push({ - id: 0, - message: 'Additional fortune added at request time.', - }); - - fortunes.sort((a, b) => (a.message < b.message ? -1 : 1)); - - return html(fortunes); - }, - { - afterHandle({ set }) { - set.headers['content-type'] = 'text/html; charset=utf-8'; - }, - } - ) - .derive(({ query }) => ({ - numberOfObjects: Math.min(parseInt(query.queries || '1') || 1, 500), - })) - .get('/queries', async ({ db, generateRandomNumber, numberOfObjects }) => { - const worldPromises = new Array>(numberOfObjects); - - for (let i = 0; i < numberOfObjects; i++) { - worldPromises[i] = db.find(generateRandomNumber()); - } + .onAfterHandle(({ set }) => { + set.headers['server'] = 'Elysia'; + }) - const worlds = await Promise.all(worldPromises); + .get('/db', () => db.find(rand())) - return worlds; + .get('/fortunes', async ({ set }) => { + const fortunes = await db.fortunes(); + + fortunes.push({ + id: 0, + message: 'Additional fortune added at request time.', + }); + + fortunes.sort((a, b) => (a.message < b.message ? -1 : 1)); + + set.headers['content-type'] = 'text/html; charset=utf-8'; + return renderTemplate(fortunes); + }) + + .get('/queries', async ({ query }) => { + const num = parseQueriesNumber(query.queries) + const worldPromises = new Array(num); + + for (let i = 0; i < num; i++) { + worldPromises[i] = db.find(rand()); + } + + return await Promise.all(worldPromises); }) - .get('/updates', async ({ db, generateRandomNumber, numberOfObjects }) => { - const worldPromises = new Array>(numberOfObjects); - for (let i = 0; i < numberOfObjects; i++) { - worldPromises[i] = db.find(generateRandomNumber()); + .get('/updates', async ({ query }) => { + const num = parseQueriesNumber(query.queries) + const worldPromises = new Array(num); + + for (let i = 0; i < num; i++) { + worldPromises[i] = db.find(rand()); } const worlds = await Promise.all(worldPromises); - for (let i = 0; i < numberOfObjects; i++) { - worlds[i].randomNumber = generateRandomNumber(); + for (let i = 0; i < num; i++) { + worlds[i].randomNumber = rand(); } await db.bulkUpdate(worlds); - return worlds; }); diff --git a/frameworks/TypeScript/elysia/src/index.ts b/frameworks/TypeScript/elysia/src/index.ts index dc0f0c8d20f..af24275c128 100644 --- a/frameworks/TypeScript/elysia/src/index.ts +++ b/frameworks/TypeScript/elysia/src/index.ts @@ -3,23 +3,27 @@ import dbHandlers from './db-handlers'; const app = new Elysia({ serve: { - // @ts-ignore reusePort: true, }, }) - .onAfterHandle(({ set }) => { + .get('/plaintext', ({ set }) => { set.headers['server'] = 'Elysia'; + return 'Hello, World!'; }) - .decorate('HELLO_WORLD_STR', 'Hello, World!') - .get('/plaintext', ({ HELLO_WORLD_STR }) => HELLO_WORLD_STR) - .get('/json', ({ HELLO_WORLD_STR }) => ({ message: HELLO_WORLD_STR })); -if (process.env.DATABASE) { + .get('/json', ({ set }) => { + set.headers = { + 'content-type': 'application/json', + 'server': 'Elysia', + }; + + return JSON.stringify({ message: 'Hello, World!' }); + }); + +if (Bun.env.DATABASE) { app.use(dbHandlers); } app.listen(8080); -console.info( - `🦊 Elysia is running at ${app.server?.hostname}:${app.server?.port}` -); +console.info(`🦊 Elysia is running at ${app.server!.url}`); diff --git a/frameworks/TypeScript/elysia/src/postgres.ts b/frameworks/TypeScript/elysia/src/postgres.ts index ae101fc0867..5c9ba1dbcbe 100644 --- a/frameworks/TypeScript/elysia/src/postgres.ts +++ b/frameworks/TypeScript/elysia/src/postgres.ts @@ -9,16 +9,16 @@ const sql = postgres({ max: 1, }); -export const fortunes = async () => - await sql`SELECT id, message FROM fortune`; +export const fortunes = () => + sql`SELECT id, message FROM fortune`; -export const find = async (id: number) => - await sql`SELECT id, randomNumber FROM world WHERE id = ${id}`.then( +export const find = (id: number) => + sql`SELECT id, randomNumber FROM world WHERE id = ${id}`.then( (arr) => arr[0] ); -export const bulkUpdate = async (worlds: World[]) => - await sql`UPDATE world SET randomNumber = (update_data.randomNumber)::int +export const bulkUpdate = (worlds: World[]) => + sql`UPDATE world SET randomNumber = (update_data.randomNumber)::int FROM (VALUES ${sql( worlds .map((world) => [world.id, world.randomNumber]) diff --git a/frameworks/TypeScript/elysia/src/types.ts b/frameworks/TypeScript/elysia/src/types.ts index a40a9a0c7b2..6863ea8f4aa 100644 --- a/frameworks/TypeScript/elysia/src/types.ts +++ b/frameworks/TypeScript/elysia/src/types.ts @@ -1,9 +1,9 @@ -export type Fortune = { - id: number; - message: string; -}; +export interface Fortune { + id: number + message: string +} -export type World = { - id: number; - randomNumber: number; -}; +export interface World { + id: number + randomNumber: number +} From b669efdbd0df11fe54e0551294f4fc03e5ea9c96 Mon Sep 17 00:00:00 2001 From: Petrik de Heus Date: Wed, 14 Aug 2024 17:36:05 +0200 Subject: [PATCH 078/204] [ruby/sinatra-sequel] Use erb for templates (#8990) erb templates have better performance than slim templates. This also makes it more inline with the Ruby/sinatra tests, which also use erb. --- frameworks/Ruby/sinatra-sequel/Gemfile | 1 - frameworks/Ruby/sinatra-sequel/hello_world.rb | 5 +---- frameworks/Ruby/sinatra-sequel/views/fortunes.erb | 12 ++++++++++++ frameworks/Ruby/sinatra-sequel/views/fortunes.slim | 8 -------- frameworks/Ruby/sinatra-sequel/views/layout.erb | 11 +++++++++++ frameworks/Ruby/sinatra-sequel/views/layout.slim | 6 ------ 6 files changed, 24 insertions(+), 19 deletions(-) create mode 100644 frameworks/Ruby/sinatra-sequel/views/fortunes.erb delete mode 100644 frameworks/Ruby/sinatra-sequel/views/fortunes.slim create mode 100644 frameworks/Ruby/sinatra-sequel/views/layout.erb delete mode 100644 frameworks/Ruby/sinatra-sequel/views/layout.slim diff --git a/frameworks/Ruby/sinatra-sequel/Gemfile b/frameworks/Ruby/sinatra-sequel/Gemfile index 649fbcfe6bf..f4ac3eb1fe2 100644 --- a/frameworks/Ruby/sinatra-sequel/Gemfile +++ b/frameworks/Ruby/sinatra-sequel/Gemfile @@ -5,7 +5,6 @@ gem 'passenger', '~> 6.0', :platforms=>[:ruby, :mswin], :require=>false gem 'puma', '~> 6.4', :require=>false gem 'sequel', '~> 5.0' gem 'sinatra', '~> 3.0', :require=>'sinatra/base' -gem 'slim', '~> 3.0' gem 'unicorn', '~> 6.1', :platforms=>[:ruby, :mswin], :require=>false group :mysql do diff --git a/frameworks/Ruby/sinatra-sequel/hello_world.rb b/frameworks/Ruby/sinatra-sequel/hello_world.rb index e04d76a077b..822ceb5979c 100644 --- a/frameworks/Ruby/sinatra-sequel/hello_world.rb +++ b/frameworks/Ruby/sinatra-sequel/hello_world.rb @@ -1,8 +1,5 @@ # frozen_string_literal: true -# Configure Slim templating engine -Slim::Engine.set_options :format=>:html, :sort_attrs=>false - # Our Rack application to be executed by rackup class HelloWorld < Sinatra::Base configure do @@ -73,7 +70,7 @@ def rand1 ) @fortunes.sort_by!(&:message) - slim :fortunes + erb :fortunes, :layout=>true end # Test type 5: Database updates diff --git a/frameworks/Ruby/sinatra-sequel/views/fortunes.erb b/frameworks/Ruby/sinatra-sequel/views/fortunes.erb new file mode 100644 index 00000000000..3d27f4dc50f --- /dev/null +++ b/frameworks/Ruby/sinatra-sequel/views/fortunes.erb @@ -0,0 +1,12 @@ + + + + + +<% @fortunes.each do |fortune| %> + + + + +<% end %> +
idmessage
<%= fortune.id %><%= Rack::Utils.escape_html(fortune.message) %>
diff --git a/frameworks/Ruby/sinatra-sequel/views/fortunes.slim b/frameworks/Ruby/sinatra-sequel/views/fortunes.slim deleted file mode 100644 index 14c18a58bc7..00000000000 --- a/frameworks/Ruby/sinatra-sequel/views/fortunes.slim +++ /dev/null @@ -1,8 +0,0 @@ -table - tr - th id - th message - - for fortune in @fortunes - tr - td =fortune.id - td =fortune.message \ No newline at end of file diff --git a/frameworks/Ruby/sinatra-sequel/views/layout.erb b/frameworks/Ruby/sinatra-sequel/views/layout.erb new file mode 100644 index 00000000000..7d6715a3e98 --- /dev/null +++ b/frameworks/Ruby/sinatra-sequel/views/layout.erb @@ -0,0 +1,11 @@ + + + + Fortunes + + + +<%= yield %> + + + diff --git a/frameworks/Ruby/sinatra-sequel/views/layout.slim b/frameworks/Ruby/sinatra-sequel/views/layout.slim deleted file mode 100644 index 2be47605c04..00000000000 --- a/frameworks/Ruby/sinatra-sequel/views/layout.slim +++ /dev/null @@ -1,6 +0,0 @@ -doctype html -html - head - title Fortunes - body - == yield \ No newline at end of file From 02764ebed3b95d09611908ee3b50c7e6c5881462 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 19 Aug 2024 08:33:58 -0700 Subject: [PATCH 079/204] Bump webob from 1.7.2 to 1.8.8 in /frameworks/Python/morepath (#9215) Bumps [webob](https://github.com/Pylons/webob) from 1.7.2 to 1.8.8. - [Changelog](https://github.com/Pylons/webob/blob/main/CHANGES.txt) - [Commits](https://github.com/Pylons/webob/compare/1.7.2...1.8.8) --- updated-dependencies: - dependency-name: webob dependency-type: direct:production ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- frameworks/Python/morepath/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frameworks/Python/morepath/requirements.txt b/frameworks/Python/morepath/requirements.txt index b1ff4b72a3a..8f58488b64e 100644 --- a/frameworks/Python/morepath/requirements.txt +++ b/frameworks/Python/morepath/requirements.txt @@ -12,6 +12,6 @@ pony==0.7.1 psycopg2==2.7.5 reg==0.11 repoze.lru==0.6 -WebOb==1.7.2 +WebOb==1.8.8 -e . From 9c9b8678aabb9aa783f8379c8cd0e318771cd0b5 Mon Sep 17 00:00:00 2001 From: LLT21 <43903768+LLT21@users.noreply.github.com> Date: Thu, 22 Aug 2024 21:06:15 +0200 Subject: [PATCH 080/204] Appmpowerv8.0.5: using native AOT dll instead of exe (#9214) * New Npgsql security update * Middleware alternative * NativeAOT calls * hellloWorld -> helloWorld * Reduce external calls * JsonMiddleware * JsonMessage built in NativeAOT * mac dylibs * Size and content separate * Small corrections * JsonMessage * JsonMessage struct * Rename nativeAOT -> appMpowerAot * Working single query, but slow * Odbc test * dockerfile changes * Try to get correct capitalization * 2nd part trial for correct capitalization * Dbms and DbProvider parameterization * linux-x64 * NativeMethods * Kestrel header * Header http * Using marshalling and out parameter * Header changes * FreeUnmanagedPointer * Correction single query * JsonMessage pointer handling * Native last methods for JsonMessage and hello world * Sync db read * Create new json message * Rename appMpowerAot -> appMpower.Orm * Fortunes * Synchronous fortunes read * Server settings * Empty line * More correct special characters length * Remove ADO and InternalConnection * Synchronous only * Cleanup * Name changes * Multiple queries * Cleanup * Alternative native methods * MultipleUpdates * odbcCommand dictionary * keyed commands * Refactoring * Remove comments * First MySQL trial * MySQL odbc * zip file mariadb connector * Better download ? * dockerfile cleanup * charset * Cached queries * Improved caching * Improved caching * Removal unnecessary packages * Cleanup project * appMpower cleanup * appMpower.Orm cleanup * Too much cleanup --------- Co-authored-by: LLT21 <> --- .../appmpower/appmpower-ado-pg.dockerfile | 17 - .../appmpower/appmpower-odbc-my.dockerfile | 51 ++ .../appmpower/appmpower-odbc-pg.dockerfile | 8 +- .../CSharp/appmpower/appmpower.dockerfile | 6 + .../CSharp/appmpower/benchmark_config.json | 8 +- frameworks/CSharp/appmpower/config.toml | 4 +- frameworks/CSharp/appmpower/odbcinst.ini | 10 + .../appmpower/src/CachedWorldSerializer.cs | 15 - .../CSharp/appmpower/src/Data/DbConnection.cs | 200 ------- .../appmpower/src/Data/DbConnections.cs | 67 --- .../appmpower/src/Data/DbProviderFactory.cs | 17 - .../appmpower/src/Data/InternalConnection.cs | 16 - .../CSharp/appmpower/src/HttpApplication.cs | 117 ---- .../CSharp/appmpower/src/JsonMessage.cs | 7 - .../CSharp/appmpower/src/Kestrel/Json.cs | 58 -- .../CSharp/appmpower/src/Kestrel/PlainText.cs | 38 -- .../appmpower/src/Kestrel/ServiceProvider.cs | 25 - .../CSharp/appmpower/src/Memory/CacheEntry.cs | 257 --------- .../appmpower/src/Memory/CacheEntryHelper.cs | 32 -- .../appmpower/src/Memory/CacheEntryState.cs | 62 --- .../appmpower/src/Memory/CacheEntryTokens.cs | 140 ----- .../appmpower/src/Memory/MemoryCache.cs | 520 ------------------ .../src/Memory/MemoryCacheOptions.cs | 67 --- .../CSharp/appmpower/src/Microsoft/CachKey.cs | 24 - .../src/Microsoft/StringBuilderCache.cs | 59 -- frameworks/CSharp/appmpower/src/Program.cs | 42 -- frameworks/CSharp/appmpower/src/RawDb.cs | 331 ----------- .../appmpower/src/appMpower.Orm/Constants.cs | 10 + .../src/{ => appMpower.Orm}/Data/DbCommand.cs | 105 ++-- .../src/appMpower.Orm/Data/DbConnection.cs | 153 ++++++ .../src/appMpower.Orm/Data/DbConnections.cs | 61 ++ .../src/appMpower.Orm/Data/DbProvider.cs | 8 + .../appMpower.Orm/Data/DbProviderFactory.cs | 21 + .../appmpower/src/appMpower.Orm/Data/Dbms.cs | 9 + .../src/appMpower.Orm/DotnetMethods.cs | 66 +++ .../src/{ => appMpower.Orm}/FortunesView.cs | 21 +- .../Microsoft/BatchUpdateString.cs | 56 +- .../Microsoft/ConcurrentRandom.cs | 2 - .../Microsoft/StringBuilderCache.cs | 54 ++ .../src/appMpower.Orm/NativeMethods.cs | 144 +++++ .../Objects}/CachedWorld.cs | 2 +- .../{ => appMpower.Orm/Objects}/Fortune.cs | 4 +- .../src/{ => appMpower.Orm/Objects}/World.cs | 2 +- .../appmpower/src/appMpower.Orm/RawDb.cs | 257 +++++++++ .../Serializers/IJsonSerializer.cs | 9 + .../Serializers}/WorldSerializer.cs | 6 +- .../Serializers/WorldsSerizalizer.cs | 24 + .../appMpower.Orm.csproj} | 97 ++-- .../appmpower/src/appMpower/JsonMessage.cs | 7 + .../appMpower/Middleware/CachingMiddelware.cs | 120 ++++ .../Middleware/FortunesMiddleware.cs | 58 ++ .../appMpower/Middleware/JsonMiddleware.cs | 64 +++ .../Middleware/MultipleQueriesMiddleware.cs | 62 +++ .../Middleware/MultipleUpdatesMiddleware.cs | 62 +++ .../Middleware/PlaintextMiddleware.cs | 50 ++ .../Middleware/SingleQueryMiddleware.cs | 57 ++ .../appmpower/src/appMpower/NativeMethods.cs | 62 +++ .../CSharp/appmpower/src/appMpower/Program.cs | 44 ++ .../Serializers}/IJsonSerializer.cs | 2 +- .../Serializers}/JsonMessageSerializer.cs | 6 +- .../CSharp/appmpower/src/appMpower/Startup.cs | 56 ++ .../appmpower/src/appMpower/appMpower.csproj | 35 ++ .../appmpower/src/appMpower/appsettings.json | 9 + .../src/{ => appMpower}/nuget.config | 0 frameworks/CSharp/appmpower/src/src.sln | 28 + 65 files changed, 1728 insertions(+), 2303 deletions(-) delete mode 100644 frameworks/CSharp/appmpower/appmpower-ado-pg.dockerfile create mode 100644 frameworks/CSharp/appmpower/appmpower-odbc-my.dockerfile delete mode 100644 frameworks/CSharp/appmpower/src/CachedWorldSerializer.cs delete mode 100644 frameworks/CSharp/appmpower/src/Data/DbConnection.cs delete mode 100644 frameworks/CSharp/appmpower/src/Data/DbConnections.cs delete mode 100644 frameworks/CSharp/appmpower/src/Data/DbProviderFactory.cs delete mode 100644 frameworks/CSharp/appmpower/src/Data/InternalConnection.cs delete mode 100644 frameworks/CSharp/appmpower/src/HttpApplication.cs delete mode 100644 frameworks/CSharp/appmpower/src/JsonMessage.cs delete mode 100644 frameworks/CSharp/appmpower/src/Kestrel/Json.cs delete mode 100644 frameworks/CSharp/appmpower/src/Kestrel/PlainText.cs delete mode 100644 frameworks/CSharp/appmpower/src/Kestrel/ServiceProvider.cs delete mode 100644 frameworks/CSharp/appmpower/src/Memory/CacheEntry.cs delete mode 100644 frameworks/CSharp/appmpower/src/Memory/CacheEntryHelper.cs delete mode 100644 frameworks/CSharp/appmpower/src/Memory/CacheEntryState.cs delete mode 100644 frameworks/CSharp/appmpower/src/Memory/CacheEntryTokens.cs delete mode 100644 frameworks/CSharp/appmpower/src/Memory/MemoryCache.cs delete mode 100644 frameworks/CSharp/appmpower/src/Memory/MemoryCacheOptions.cs delete mode 100644 frameworks/CSharp/appmpower/src/Microsoft/CachKey.cs delete mode 100644 frameworks/CSharp/appmpower/src/Microsoft/StringBuilderCache.cs delete mode 100644 frameworks/CSharp/appmpower/src/Program.cs delete mode 100644 frameworks/CSharp/appmpower/src/RawDb.cs create mode 100644 frameworks/CSharp/appmpower/src/appMpower.Orm/Constants.cs rename frameworks/CSharp/appmpower/src/{ => appMpower.Orm}/Data/DbCommand.cs (52%) create mode 100644 frameworks/CSharp/appmpower/src/appMpower.Orm/Data/DbConnection.cs create mode 100644 frameworks/CSharp/appmpower/src/appMpower.Orm/Data/DbConnections.cs create mode 100644 frameworks/CSharp/appmpower/src/appMpower.Orm/Data/DbProvider.cs create mode 100644 frameworks/CSharp/appmpower/src/appMpower.Orm/Data/DbProviderFactory.cs create mode 100644 frameworks/CSharp/appmpower/src/appMpower.Orm/Data/Dbms.cs create mode 100644 frameworks/CSharp/appmpower/src/appMpower.Orm/DotnetMethods.cs rename frameworks/CSharp/appmpower/src/{ => appMpower.Orm}/FortunesView.cs (54%) rename frameworks/CSharp/appmpower/src/{ => appMpower.Orm}/Microsoft/BatchUpdateString.cs (54%) rename frameworks/CSharp/appmpower/src/{ => appMpower.Orm}/Microsoft/ConcurrentRandom.cs (95%) create mode 100644 frameworks/CSharp/appmpower/src/appMpower.Orm/Microsoft/StringBuilderCache.cs create mode 100644 frameworks/CSharp/appmpower/src/appMpower.Orm/NativeMethods.cs rename frameworks/CSharp/appmpower/src/{ => appMpower.Orm/Objects}/CachedWorld.cs (88%) rename frameworks/CSharp/appmpower/src/{ => appMpower.Orm/Objects}/Fortune.cs (93%) rename frameworks/CSharp/appmpower/src/{ => appMpower.Orm/Objects}/World.cs (78%) create mode 100644 frameworks/CSharp/appmpower/src/appMpower.Orm/RawDb.cs create mode 100644 frameworks/CSharp/appmpower/src/appMpower.Orm/Serializers/IJsonSerializer.cs rename frameworks/CSharp/appmpower/src/{ => appMpower.Orm/Serializers}/WorldSerializer.cs (68%) create mode 100644 frameworks/CSharp/appmpower/src/appMpower.Orm/Serializers/WorldsSerizalizer.cs rename frameworks/CSharp/appmpower/src/{appMpower.csproj => appMpower.Orm/appMpower.Orm.csproj} (52%) create mode 100644 frameworks/CSharp/appmpower/src/appMpower/JsonMessage.cs create mode 100644 frameworks/CSharp/appmpower/src/appMpower/Middleware/CachingMiddelware.cs create mode 100644 frameworks/CSharp/appmpower/src/appMpower/Middleware/FortunesMiddleware.cs create mode 100644 frameworks/CSharp/appmpower/src/appMpower/Middleware/JsonMiddleware.cs create mode 100644 frameworks/CSharp/appmpower/src/appMpower/Middleware/MultipleQueriesMiddleware.cs create mode 100644 frameworks/CSharp/appmpower/src/appMpower/Middleware/MultipleUpdatesMiddleware.cs create mode 100644 frameworks/CSharp/appmpower/src/appMpower/Middleware/PlaintextMiddleware.cs create mode 100644 frameworks/CSharp/appmpower/src/appMpower/Middleware/SingleQueryMiddleware.cs create mode 100644 frameworks/CSharp/appmpower/src/appMpower/NativeMethods.cs create mode 100644 frameworks/CSharp/appmpower/src/appMpower/Program.cs rename frameworks/CSharp/appmpower/src/{Kestrel => appMpower/Serializers}/IJsonSerializer.cs (81%) rename frameworks/CSharp/appmpower/src/{ => appMpower/Serializers}/JsonMessageSerializer.cs (58%) create mode 100644 frameworks/CSharp/appmpower/src/appMpower/Startup.cs create mode 100644 frameworks/CSharp/appmpower/src/appMpower/appMpower.csproj create mode 100644 frameworks/CSharp/appmpower/src/appMpower/appsettings.json rename frameworks/CSharp/appmpower/src/{ => appMpower}/nuget.config (100%) create mode 100644 frameworks/CSharp/appmpower/src/src.sln diff --git a/frameworks/CSharp/appmpower/appmpower-ado-pg.dockerfile b/frameworks/CSharp/appmpower/appmpower-ado-pg.dockerfile deleted file mode 100644 index 2e7234ca98d..00000000000 --- a/frameworks/CSharp/appmpower/appmpower-ado-pg.dockerfile +++ /dev/null @@ -1,17 +0,0 @@ -FROM mcr.microsoft.com/dotnet/sdk:8.0.100 AS build -RUN apt-get update -RUN apt-get -yqq install clang zlib1g-dev libkrb5-dev libtinfo5 - -WORKDIR /app -COPY src . -RUN dotnet publish -c Release -o out /p:Driver=ado - -# Construct the actual image that will run -FROM mcr.microsoft.com/dotnet/aspnet:8.0.0 AS runtime - -WORKDIR /app -COPY --from=build /app/out ./ - -EXPOSE 8080 - -ENTRYPOINT ["./appMpower"] \ No newline at end of file diff --git a/frameworks/CSharp/appmpower/appmpower-odbc-my.dockerfile b/frameworks/CSharp/appmpower/appmpower-odbc-my.dockerfile new file mode 100644 index 00000000000..a5bbf22ae6f --- /dev/null +++ b/frameworks/CSharp/appmpower/appmpower-odbc-my.dockerfile @@ -0,0 +1,51 @@ +FROM mcr.microsoft.com/dotnet/sdk:8.0.100 AS build +RUN apt-get update +RUN apt-get -yqq install clang zlib1g-dev +RUN apt-get update + +WORKDIR /app +COPY src . +RUN dotnet publish -c Release -o out /p:Database=mysql + +# Construct the actual image that will run +FROM mcr.microsoft.com/dotnet/aspnet:8.0.0 AS runtime + +RUN apt-get update +# The following installs standard versions unixodbc and pgsqlodbc +# unixodbc still needs to be installed even if compiled locally +RUN apt-get install -y unixodbc wget curl +RUN apt-get update + +WORKDIR /odbc + +RUN curl -L -o mariadb-connector-odbc-3.1.20-debian-bookworm-amd64.tar.gz https://downloads.mariadb.com/Connectors/odbc/connector-odbc-3.1.20/mariadb-connector-odbc-3.1.20-debian-bookworm-amd64.tar.gz +RUN tar -xvzf mariadb-connector-odbc-3.1.20-debian-bookworm-amd64.tar.gz +RUN cp mariadb-connector-odbc-3.1.20-debian-bookworm-amd64/lib/mariadb/libm* /usr/lib/ +RUN cp -r /odbc/mariadb-connector-odbc-3.1.20-debian-bookworm-amd64/lib/mariadb /usr/local/lib/mariadb +RUN rm mariadb-connector-odbc-3.1.20-debian-bookworm-amd64.tar.gz +#TODOLOCAL +#RUN curl -L -o mariadb-connector-odbc-3.1.20-debian-bookworm-aarch64.tar.gz https://downloads.mariadb.com/Connectors/odbc/connector-odbc-3.1.20/mariadb-connector-odbc-3.1.20-debian-bookworm-aarch64.tar.gz +#RUN tar -xvzf mariadb-connector-odbc-3.1.20-debian-bookworm-aarch64.tar.gz +#RUN cp mariadb-connector-odbc-3.1.20-debian-bookworm-aarch64/lib/mariadb/libm* /usr/lib/ +#RUN cp -r /odbc/mariadb-connector-odbc-3.1.20-debian-bookworm-aarch64/lib/mariadb /usr/local/lib/mariadb +#RUN rm mariadb-connector-odbc-3.1.20-debian-bookworm-aarch64.tar.gz + +ENV PATH=/usr/local/unixODBC/bin:$PATH + +WORKDIR /etc/ +COPY odbcinst.ini . + +# Full PGO +ENV DOTNET_TieredPGO 1 +ENV DOTNET_TC_QuickJitForLoops 1 +ENV DOTNET_ReadyToRun 0 + +ENV ASPNETCORE_URLS http://+:8080 +WORKDIR /app +COPY --from=build /app/out ./ + +RUN cp /usr/lib/libm* /app + +EXPOSE 8080 + +ENTRYPOINT ["./appMpower"] \ No newline at end of file diff --git a/frameworks/CSharp/appmpower/appmpower-odbc-pg.dockerfile b/frameworks/CSharp/appmpower/appmpower-odbc-pg.dockerfile index c06865cc0b2..4080684bab6 100644 --- a/frameworks/CSharp/appmpower/appmpower-odbc-pg.dockerfile +++ b/frameworks/CSharp/appmpower/appmpower-odbc-pg.dockerfile @@ -4,7 +4,7 @@ RUN apt-get -yqq install clang zlib1g-dev libkrb5-dev libtinfo5 WORKDIR /app COPY src . -RUN dotnet publish -c Release -o out /p:Driver=odbc +RUN dotnet publish -c Release -o out /p:Database=postgresql # Construct the actual image that will run FROM mcr.microsoft.com/dotnet/aspnet:8.0.0 AS runtime @@ -18,6 +18,12 @@ ENV PATH=/usr/local/unixODBC/bin:$PATH WORKDIR /etc/ COPY odbcinst.ini . +# Full PGO +ENV DOTNET_TieredPGO 1 +ENV DOTNET_TC_QuickJitForLoops 1 +ENV DOTNET_ReadyToRun 0 + +ENV ASPNETCORE_URLS http://+:8080 WORKDIR /app COPY --from=build /app/out ./ diff --git a/frameworks/CSharp/appmpower/appmpower.dockerfile b/frameworks/CSharp/appmpower/appmpower.dockerfile index 7f77873dfaf..3d521c490d8 100644 --- a/frameworks/CSharp/appmpower/appmpower.dockerfile +++ b/frameworks/CSharp/appmpower/appmpower.dockerfile @@ -4,11 +4,17 @@ RUN apt-get -yqq install clang zlib1g-dev libkrb5-dev libtinfo5 WORKDIR /app COPY src . +#RUN dotnet publish appMpower/appMpower.csproj -c Release -o out RUN dotnet publish -c Release -o out # Construct the actual image that will run FROM mcr.microsoft.com/dotnet/aspnet:8.0.0 AS runtime +# Full PGO +ENV DOTNET_TieredPGO 1 +ENV DOTNET_TC_QuickJitForLoops 1 +ENV DOTNET_ReadyToRun 0 +ENV ASPNETCORE_URLS http://+:8080 WORKDIR /app COPY --from=build /app/out ./ diff --git a/frameworks/CSharp/appmpower/benchmark_config.json b/frameworks/CSharp/appmpower/benchmark_config.json index 6c22c0c65af..46dc7e7c00f 100644 --- a/frameworks/CSharp/appmpower/benchmark_config.json +++ b/frameworks/CSharp/appmpower/benchmark_config.json @@ -39,11 +39,11 @@ "webserver": "Kestrel", "os": "Linux", "database_os": "Linux", - "display_name": "appMpower [aot-no-reflection,odbc]", + "display_name": "appMpower [aot-no-reflection,pg,odbc]", "notes": "", "versus": "aspnetcore-minimal" }, - "ado-pg": { + "odbc-my": { "db_url": "/db", "query_url": "/queries?c=", "update_url": "/updates?c=", @@ -52,7 +52,7 @@ "port": 8080, "approach": "Realistic", "classification": "Platform", - "database": "Postgres", + "database": "MySQL", "framework": "appmpower", "language": "C#", "orm": "Raw", @@ -61,7 +61,7 @@ "webserver": "Kestrel", "os": "Linux", "database_os": "Linux", - "display_name": "appMpower [aot-no-reflection,ado]", + "display_name": "appMpower [aot-no-reflection,my,odbc]", "notes": "", "versus": "aspnetcore-minimal" } diff --git a/frameworks/CSharp/appmpower/config.toml b/frameworks/CSharp/appmpower/config.toml index d500b2df989..a3747682191 100644 --- a/frameworks/CSharp/appmpower/config.toml +++ b/frameworks/CSharp/appmpower/config.toml @@ -30,7 +30,7 @@ platform = ".NET" webserver = "Kestrel" versus = "aspnetcore-minimal" -[ado-pg] +[odbc-my] urls.db = "/db" urls.query = "/queries?c=" urls.update = "/updates?c=" @@ -38,7 +38,7 @@ urls.fortune = "/fortunes" urls.cached_query = "/cached-worlds?c=" approach = "Realistic" classification = "Micro" -database = "Postgres" +database = "MySQL" database_os = "Linux" os = "Linux" orm = "Raw" diff --git a/frameworks/CSharp/appmpower/odbcinst.ini b/frameworks/CSharp/appmpower/odbcinst.ini index c6260e38b93..544ba2067c1 100644 --- a/frameworks/CSharp/appmpower/odbcinst.ini +++ b/frameworks/CSharp/appmpower/odbcinst.ini @@ -5,6 +5,7 @@ Pooling=0 [ODBC Drivers] PostgreSQL = Installed +MariaDB = Installed ; ; odbcinst.ini @@ -15,7 +16,16 @@ Description=ODBC for PostgreSQL ; in version 08.x. Note that the library can also be installed under an other ; path than /usr/local/lib/ following your installation. ; This is the standard location used by apt-get install -y unixodbc +;ON SERVER Driver = /usr/lib/x86_64-linux-gnu/odbc/psqlodbcw.so +;TODOLOCAL: ON MAC +;Driver =/usr/lib/aarch64-linux-gnu/odbc/psqlodbcw.so + ;Driver =/usr/local/pgsqlodbc/lib/psqlodbcw.so Threading = 0 CPTimeout = 0 + +[MariaDB] +Description=MariaDB ODBC for MySQL +Driver = /usr/lib/libmaodbc.so +Threading = 0 \ No newline at end of file diff --git a/frameworks/CSharp/appmpower/src/CachedWorldSerializer.cs b/frameworks/CSharp/appmpower/src/CachedWorldSerializer.cs deleted file mode 100644 index f7c78b6dd65..00000000000 --- a/frameworks/CSharp/appmpower/src/CachedWorldSerializer.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System.Text.Json; - -namespace appMpower -{ - public class CachedWorldSerializer : Kestrel.IJsonSerializer - { - public void Serialize(Utf8JsonWriter utf8JsonWriter, CachedWorld world) - { - utf8JsonWriter.WriteStartObject(); - utf8JsonWriter.WriteNumber("id", world.Id); - utf8JsonWriter.WriteNumber("randomNumber", world.RandomNumber); - utf8JsonWriter.WriteEndObject(); - } - } -} \ No newline at end of file diff --git a/frameworks/CSharp/appmpower/src/Data/DbConnection.cs b/frameworks/CSharp/appmpower/src/Data/DbConnection.cs deleted file mode 100644 index 916e251a9c8..00000000000 --- a/frameworks/CSharp/appmpower/src/Data/DbConnection.cs +++ /dev/null @@ -1,200 +0,0 @@ -using System.Collections.Concurrent; -using System.Data; -using System.Threading.Tasks; - -namespace appMpower.Data -{ - public class DbConnection : IDbConnection - { - private string _connectionString; - internal InternalConnection _internalConnection; - - public DbConnection() - { - _connectionString = DbProviderFactory.ConnectionString; - } - - public DbConnection(string connectionString) - { - _connectionString = connectionString; - } - - internal ConcurrentDictionary DbCommands - { - get - { - return _internalConnection.DbCommands; - } - set - { - _internalConnection.DbCommands = value; - } - } - - public short Number - { - get - { - return _internalConnection.Number; - } - set - { - _internalConnection.Number = value; - } - } - - public IDbConnection Connection - { - get - { - return _internalConnection.DbConnection; - } - set - { - _internalConnection.DbConnection = value; - } - } - - public string ConnectionString - { - get - { - return _internalConnection.DbConnection.ConnectionString; - } - set - { - _internalConnection.DbConnection.ConnectionString = value; - } - } - - public int ConnectionTimeout - { - get - { - return _internalConnection.DbConnection.ConnectionTimeout; - } - } - - public string Database - { - get - { - return _internalConnection.DbConnection.Database; - } - } - - public ConnectionState State - { - get - { - if (_internalConnection is null) return ConnectionState.Closed; - return _internalConnection.DbConnection.State; - } - } - - public IDbTransaction BeginTransaction() - { - return _internalConnection.DbConnection.BeginTransaction(); - } - - public IDbTransaction BeginTransaction(IsolationLevel il) - { - return _internalConnection.DbConnection.BeginTransaction(il); - } - - public void ChangeDatabase(string databaseName) - { - _internalConnection.DbConnection.ChangeDatabase(databaseName); - } - - public void Close() - { - _internalConnection.DbConnection.Close(); - } - - public async Task CloseAsync() - { - await (_internalConnection.DbConnection as System.Data.Common.DbConnection).CloseAsync(); - } - - public IDbCommand CreateCommand() - { - return _internalConnection.DbConnection.CreateCommand(); - } - - public void Open() - { - if (_internalConnection.DbConnection.State == ConnectionState.Closed) - { - _internalConnection.DbConnection.Open(); - } - } - - public void Dispose() - { -#if ADO - _internalConnection.DbConnection.Dispose(); - _internalConnection.Dispose(); -#else - DbConnections.Release(_internalConnection); -#endif - } - - public async Task OpenAsync() - { -#if ADO && POSTGRESQL - _internalConnection = new(); - _internalConnection.DbConnection = new Npgsql.NpgsqlConnection(_connectionString); -#else - if (_internalConnection is null) - { - _internalConnection = await DbConnections.GetConnection(_connectionString); - } -#endif - - if (_internalConnection.DbConnection.State == ConnectionState.Closed) - { - await (_internalConnection.DbConnection as System.Data.Common.DbConnection).OpenAsync(); - } - } - - internal DbCommand GetCommand(string commandText, CommandType commandType, DbCommand dbCommand) - { -#if ADO - dbCommand.Command = _internalConnection.DbConnection.CreateCommand(); - dbCommand.Command.CommandText = commandText; - dbCommand.Command.CommandType = commandType; - dbCommand.DbConnection = this; -#else - DbCommand internalCommand; - - if (_internalConnection.DbCommands.TryRemove(commandText, out internalCommand)) - { - dbCommand.Command = internalCommand.Command; - dbCommand.DbConnection = internalCommand.DbConnection; - } - else - { - dbCommand.Command = _internalConnection.DbConnection.CreateCommand(); - dbCommand.Command.CommandText = commandText; - dbCommand.Command.CommandType = commandType; - dbCommand.DbConnection = this; - - //For non odbc drivers like Npgsql which do not support Prepare - dbCommand.Command.Prepare(); - - //Console.WriteLine("prepare pool connection: " + this._internalConnection.Number + " for command " + _internalConnection.DbCommands.Count); - } -#endif - - return dbCommand; - } - - public void ReleaseCommand(DbCommand dbCommand) - { -#if !ADO - _internalConnection.DbCommands.TryAdd(dbCommand.CommandText, dbCommand); -#endif - } - } -} \ No newline at end of file diff --git a/frameworks/CSharp/appmpower/src/Data/DbConnections.cs b/frameworks/CSharp/appmpower/src/Data/DbConnections.cs deleted file mode 100644 index 0b513a3d47f..00000000000 --- a/frameworks/CSharp/appmpower/src/Data/DbConnections.cs +++ /dev/null @@ -1,67 +0,0 @@ -using System.Collections.Concurrent; -using System.Threading.Tasks; - -namespace appMpower.Data -{ - public static class DbConnections - { - private static bool _connectionsCreated = false; - private static short _createdConnections = 0; - private static short _maxConnections = 500; - - private static ConcurrentStack _stack = new(); - private static ConcurrentQueue> _waitingQueue = new(); - - public static async Task GetConnection(string connectionString) - { - InternalConnection internalConnection = null; - - if (_connectionsCreated) - { - if (!_stack.TryPop(out internalConnection)) - { - internalConnection = await GetDbConnectionAsync(); - } - - return internalConnection; - } - else - { - internalConnection = new InternalConnection(); - internalConnection.DbConnection = new System.Data.Odbc.OdbcConnection(connectionString); - - _createdConnections++; - - if (_createdConnections == _maxConnections) _connectionsCreated = true; - - internalConnection.Number = _createdConnections; - internalConnection.DbCommands = new ConcurrentDictionary(); - //Console.WriteLine("opened connection number: " + dbConnection.Number); - - return internalConnection; - } - } - - public static Task GetDbConnectionAsync() - { - var taskCompletionSource = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); - - _waitingQueue.Enqueue(taskCompletionSource); - return taskCompletionSource.Task; - } - - public static void Release(InternalConnection internalConnection) - { - TaskCompletionSource taskCompletionSource; - - if (_waitingQueue.TryDequeue(out taskCompletionSource)) - { - taskCompletionSource.SetResult(internalConnection); - } - else - { - _stack.Push(internalConnection); - } - } - } -} \ No newline at end of file diff --git a/frameworks/CSharp/appmpower/src/Data/DbProviderFactory.cs b/frameworks/CSharp/appmpower/src/Data/DbProviderFactory.cs deleted file mode 100644 index 98a4aa67cb6..00000000000 --- a/frameworks/CSharp/appmpower/src/Data/DbProviderFactory.cs +++ /dev/null @@ -1,17 +0,0 @@ -using System.Data; - -namespace appMpower.Data -{ - public static class DbProviderFactory - { -#if MYSQL - public const string ConnectionString = "Driver={MariaDB};Server=tfb-database;Database=hello_world;Uid=benchmarkdbuser;Pwd=benchmarkdbpass;Pooling=false;OPTIONS=67108864;FLAG_FORWARD_CURSOR=1"; -#elif ADO - public const string ConnectionString = "Server=tfb-database;Database=hello_world;User Id=benchmarkdbuser;Password=benchmarkdbpass;SSL Mode=0;Maximum Pool Size=18;NoResetOnClose=true;Enlist=false;Max Auto Prepare=4;Multiplexing=true;Write Coalescing Buffer Threshold Bytes=1000"; - //public const string ConnectionString = "Server=localhost;Database=hello_world;User Id=benchmarkdbuser;Password=benchmarkdbpass;SSL Mode=Disable;Maximum Pool Size=18;NoResetOnClose=true;Enlist=false;Max Auto Prepare=4;Multiplexing=true;Write Coalescing Buffer Threshold Bytes=1000"; -#else - public const string ConnectionString = "Driver={PostgreSQL};Server=tfb-database;Database=hello_world;Uid=benchmarkdbuser;Pwd=benchmarkdbpass;UseServerSidePrepare=1;Pooling=false"; - //public const string ConnectionString = "Driver={PostgreSQL};Server=localhost;Database=hello_world;Uid=benchmarkdbuser;Pwd=benchmarkdbpass;UseServerSidePrepare=1;Pooling=false"; -#endif - } -} \ No newline at end of file diff --git a/frameworks/CSharp/appmpower/src/Data/InternalConnection.cs b/frameworks/CSharp/appmpower/src/Data/InternalConnection.cs deleted file mode 100644 index 25cecfeb4f8..00000000000 --- a/frameworks/CSharp/appmpower/src/Data/InternalConnection.cs +++ /dev/null @@ -1,16 +0,0 @@ -using System.Collections.Concurrent; -using System.Data; - -namespace appMpower.Data -{ - public class InternalConnection : System.IDisposable - { - public short Number { get; set; } - public IDbConnection DbConnection { get; set; } - public ConcurrentDictionary DbCommands { get; set; } - - public void Dispose() - { - } - } -} \ No newline at end of file diff --git a/frameworks/CSharp/appmpower/src/HttpApplication.cs b/frameworks/CSharp/appmpower/src/HttpApplication.cs deleted file mode 100644 index 1eac250ede5..00000000000 --- a/frameworks/CSharp/appmpower/src/HttpApplication.cs +++ /dev/null @@ -1,117 +0,0 @@ -using System; -using System.Text; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Hosting.Server; -using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Http.Features; -using appMpower.Kestrel; - -namespace appMpower -{ - public class HttpApplication : IHttpApplication - { - public static readonly byte[] _plainText = Encoding.UTF8.GetBytes("Hello, World!"); - private readonly static JsonMessageSerializer _jsonMessageSerializer = new JsonMessageSerializer(); - private readonly static WorldSerializer _worldSerializer = new WorldSerializer(); - private readonly static CachedWorldSerializer _cachedWorldSerializer = new CachedWorldSerializer(); - - public IFeatureCollection CreateContext(IFeatureCollection featureCollection) - { - return featureCollection; - } - - public async Task ProcessRequestAsync(IFeatureCollection featureCollection) - { - var request = featureCollection as IHttpRequestFeature; - var httpResponse = featureCollection as IHttpResponseFeature; - var httpResponseBody = featureCollection as IHttpResponseBodyFeature; - - PathString pathString = request.Path; - - if (pathString.HasValue) - { - int pathStringLength = pathString.Value.Length; - string pathStringStart = pathString.Value.Substring(1, 1); - - if (pathStringLength == 10 && pathStringStart == "p") - { - //await PlainText.RenderAsync(httpResponse.Headers, httpResponseBody.Writer, _plainText); - PlainText.Render(httpResponse.Headers, httpResponseBody, _plainText); - return; - } - else if (pathStringLength == 5 && pathStringStart == "j") - { - Json.RenderOne(httpResponse.Headers, httpResponseBody.Writer, new JsonMessage { message = "Hello, World!" }, _jsonMessageSerializer); - return; - } - else if (pathStringLength == 3 && pathStringStart == "d") - { - Json.RenderOne(httpResponse.Headers, httpResponseBody.Writer, await RawDb.LoadSingleQueryRow(), _worldSerializer); - return; - } - else if (pathStringLength == 8 && pathStringStart == "q") - { - int count = 1; - - if (!Int32.TryParse(request.QueryString.Substring(request.QueryString.LastIndexOf("=") + 1), out count) || count < 1) - { - count = 1; - } - else if (count > 500) - { - count = 500; - } - -#if ADO - Json.RenderMany(httpResponse.Headers, httpResponseBody.Writer, await RawDb.LoadMultipleQueriesRows(count), _worldSerializer); -#else - Json.RenderMany(httpResponse.Headers, httpResponseBody.Writer, await RawDb.ReadMultipleRows(count), _worldSerializer); -#endif - - return; - } - else if (pathStringLength == 9 && pathStringStart == "f") - { - await FortunesView.Render(httpResponse.Headers, httpResponseBody.Writer, await RawDb.LoadFortunesRows()); - return; - } - else if (pathStringLength == 8 && pathStringStart == "u") - { - int count = 1; - - if (!Int32.TryParse(request.QueryString.Substring(request.QueryString.LastIndexOf("=") + 1), out count) || count < 1) - { - count = 1; - } - else if (count > 500) - { - count = 500; - } - - Json.RenderMany(httpResponse.Headers, httpResponseBody.Writer, await RawDb.LoadMultipleUpdatesRows(count), _worldSerializer); - return; - } - else if (pathStringLength == 14 && pathStringStart == "c") - { - int count = 1; - - if (!Int32.TryParse(request.QueryString.Substring(request.QueryString.LastIndexOf("=") + 1), out count) || count < 1) - { - count = 1; - } - else if (count > 500) - { - count = 500; - } - - Json.RenderMany(httpResponse.Headers, httpResponseBody.Writer, await RawDb.LoadCachedQueries(count), _cachedWorldSerializer); - return; - } - } - } - - public void DisposeContext(IFeatureCollection featureCollection, Exception exception) - { - } - } -} \ No newline at end of file diff --git a/frameworks/CSharp/appmpower/src/JsonMessage.cs b/frameworks/CSharp/appmpower/src/JsonMessage.cs deleted file mode 100644 index 24b78265baa..00000000000 --- a/frameworks/CSharp/appmpower/src/JsonMessage.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace appMpower -{ - public struct JsonMessage - { - public string message { get; set; } - } -} \ No newline at end of file diff --git a/frameworks/CSharp/appmpower/src/Kestrel/Json.cs b/frameworks/CSharp/appmpower/src/Kestrel/Json.cs deleted file mode 100644 index c81028e2a9b..00000000000 --- a/frameworks/CSharp/appmpower/src/Kestrel/Json.cs +++ /dev/null @@ -1,58 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO.Pipelines; -using System.Text.Json; -using Microsoft.AspNetCore.Http; -using Microsoft.Extensions.Primitives; - -namespace appMpower.Kestrel -{ - public static class Json - { - private readonly static KeyValuePair _headerServer = - new KeyValuePair("Server", "k"); - private readonly static KeyValuePair _headerContentType = - new KeyValuePair("Content-Type", "application/json"); - - [ThreadStatic] - private static Utf8JsonWriter _utf8JsonWriter; - - public static JsonWriterOptions _jsonWriterOptions = new JsonWriterOptions - { - SkipValidation = true - }; - - public static void RenderOne(IHeaderDictionary headerDictionary, PipeWriter pipeWriter, T t, IJsonSerializer jsonSerializer) - { - headerDictionary.Add(_headerServer); - headerDictionary.Add(_headerContentType); - - Utf8JsonWriter utf8JsonWriter = _utf8JsonWriter ??= new Utf8JsonWriter(pipeWriter, new JsonWriterOptions { SkipValidation = true }); - utf8JsonWriter.Reset(pipeWriter); - - jsonSerializer.Serialize(utf8JsonWriter, t); - utf8JsonWriter.Flush(); - headerDictionary.Add(new KeyValuePair("Content-Length", utf8JsonWriter.BytesCommitted.ToString())); - } - - public static void RenderMany(IHeaderDictionary headerDictionary, PipeWriter pipeWriter, T[] tArray, IJsonSerializer jsonSerializer) - { - headerDictionary.Add(_headerServer); - headerDictionary.Add(_headerContentType); - - Utf8JsonWriter utf8JsonWriter = _utf8JsonWriter ??= new Utf8JsonWriter(pipeWriter, new JsonWriterOptions { SkipValidation = true }); - utf8JsonWriter.Reset(pipeWriter); - - utf8JsonWriter.WriteStartArray(); - - foreach (var t in tArray) - { - jsonSerializer.Serialize(utf8JsonWriter, t); - } - - utf8JsonWriter.WriteEndArray(); - utf8JsonWriter.Flush(); - headerDictionary.Add(new KeyValuePair("Content-Length", utf8JsonWriter.BytesCommitted.ToString())); - } - } -} \ No newline at end of file diff --git a/frameworks/CSharp/appmpower/src/Kestrel/PlainText.cs b/frameworks/CSharp/appmpower/src/Kestrel/PlainText.cs deleted file mode 100644 index e7ead33aa2e..00000000000 --- a/frameworks/CSharp/appmpower/src/Kestrel/PlainText.cs +++ /dev/null @@ -1,38 +0,0 @@ -using System; -using System.Threading.Tasks; -using System.Collections.Generic; -using System.IO.Pipelines; -using Microsoft.AspNetCore.Http; -using Microsoft.Extensions.Primitives; -using Microsoft.AspNetCore.Http.Features; - -namespace appMpower.Kestrel -{ - public static class PlainText - { - private readonly static KeyValuePair _headerServer = - new KeyValuePair("Server", new StringValues("k")); - private readonly static KeyValuePair _headerContentType = - new KeyValuePair("Content-Type", new StringValues("text/plain")); - - public static async Task RenderAsync(IHeaderDictionary headerDictionary, PipeWriter pipeWriter, ReadOnlyMemory utf8String) - { - headerDictionary.Add(_headerServer); - headerDictionary.Add(_headerContentType); - headerDictionary.Add(new KeyValuePair("Content-Length", utf8String.Length.ToString())); - - await pipeWriter.WriteAsync(utf8String); - pipeWriter.Complete(); - } - - public static void Render(IHeaderDictionary headerDictionary, IHttpResponseBodyFeature httpResponseBodyFeature, byte[] utf8String) - { - headerDictionary.Add(_headerServer); - headerDictionary.Add(_headerContentType); - int length = utf8String.Length; - headerDictionary.Add(new KeyValuePair("Content-Length", length.ToString())); - - httpResponseBodyFeature.Stream.Write(utf8String, 0, length); - } - } -} \ No newline at end of file diff --git a/frameworks/CSharp/appmpower/src/Kestrel/ServiceProvider.cs b/frameworks/CSharp/appmpower/src/Kestrel/ServiceProvider.cs deleted file mode 100644 index 513174e68b9..00000000000 --- a/frameworks/CSharp/appmpower/src/Kestrel/ServiceProvider.cs +++ /dev/null @@ -1,25 +0,0 @@ -using System; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Logging.Abstractions; - -namespace appMpower.Kestrel -{ - public class ServiceProvider : ISupportRequiredService, IServiceProvider - { - public object GetRequiredService(Type serviceType) - { - return GetService(serviceType); - } - - public object GetService(Type serviceType) - { - if (serviceType == typeof(ILoggerFactory)) - { - return NullLoggerFactory.Instance; - } - - return null; - } - } -} \ No newline at end of file diff --git a/frameworks/CSharp/appmpower/src/Memory/CacheEntry.cs b/frameworks/CSharp/appmpower/src/Memory/CacheEntry.cs deleted file mode 100644 index 55ca29c4984..00000000000 --- a/frameworks/CSharp/appmpower/src/Memory/CacheEntry.cs +++ /dev/null @@ -1,257 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System; -using System.Collections.Generic; -using System.Runtime.CompilerServices; -using System.Threading; -using System.Threading.Tasks; -using Microsoft.Extensions.Primitives; -using Microsoft.Extensions.Caching.Memory; - -namespace appMpower.Memory -{ - internal sealed partial class CacheEntry : ICacheEntry - { - private static readonly Action ExpirationCallback = ExpirationTokensExpired; - - private readonly MemoryCache _cache; - - private CacheEntryTokens _tokens; // might be null if user is not using the tokens or callbacks - private TimeSpan? _absoluteExpirationRelativeToNow; - private TimeSpan? _slidingExpiration; - private long? _size; - private CacheEntry _previous; // this field is not null only before the entry is added to the cache and tracking is enabled - private object _value; - private CacheEntryState _state; - - internal CacheEntry(object key, MemoryCache memoryCache) - { - Key = key ?? throw new ArgumentNullException(nameof(key)); - _cache = memoryCache ?? throw new ArgumentNullException(nameof(memoryCache)); - _previous = memoryCache.TrackLinkedCacheEntries ? CacheEntryHelper.EnterScope(this) : null; - _state = new CacheEntryState(CacheItemPriority.Normal); - } - - /// - /// Gets or sets an absolute expiration date for the cache entry. - /// - public DateTimeOffset? AbsoluteExpiration { get; set; } - - /// - /// Gets or sets an absolute expiration time, relative to now. - /// - public TimeSpan? AbsoluteExpirationRelativeToNow - { - get => _absoluteExpirationRelativeToNow; - set - { - // this method does not set AbsoluteExpiration as it would require calling Clock.UtcNow twice: - // once here and once in MemoryCache.SetEntry - - if (value <= TimeSpan.Zero) - { - throw new ArgumentOutOfRangeException( - nameof(AbsoluteExpirationRelativeToNow), - value, - "The relative expiration value must be positive."); - } - - _absoluteExpirationRelativeToNow = value; - } - } - - /// - /// Gets or sets how long a cache entry can be inactive (e.g. not accessed) before it will be removed. - /// This will not extend the entry lifetime beyond the absolute expiration (if set). - /// - public TimeSpan? SlidingExpiration - { - get => _slidingExpiration; - set - { - if (value <= TimeSpan.Zero) - { - throw new ArgumentOutOfRangeException( - nameof(SlidingExpiration), - value, - "The sliding expiration value must be positive."); - } - - _slidingExpiration = value; - } - } - - /// - /// Gets the instances which cause the cache entry to expire. - /// - public IList ExpirationTokens => GetOrCreateTokens().ExpirationTokens; - - /// - /// Gets or sets the callbacks will be fired after the cache entry is evicted from the cache. - /// - public IList PostEvictionCallbacks => GetOrCreateTokens().PostEvictionCallbacks; - - /// - /// Gets or sets the priority for keeping the cache entry in the cache during a - /// memory pressure triggered cleanup. The default is . - /// - public CacheItemPriority Priority { get => _state.Priority; set => _state.Priority = value; } - - /// - /// Gets or sets the size of the cache entry value. - /// - public long? Size - { - get => _size; - set - { - if (value < 0) - { - throw new ArgumentOutOfRangeException(nameof(value), value, $"{nameof(value)} must be non-negative."); - } - - _size = value; - } - } - - public object Key { get; private set; } - - public object Value - { - get => _value; - set - { - _value = value; - _state.IsValueSet = true; - } - } - - internal DateTimeOffset LastAccessed { get; set; } - - internal EvictionReason EvictionReason { get => _state.EvictionReason; private set => _state.EvictionReason = value; } - - public void Dispose() - { - if (!_state.IsDisposed) - { - _state.IsDisposed = true; - - if (_cache.TrackLinkedCacheEntries) - { - CacheEntryHelper.ExitScope(this, _previous); - } - - // Don't commit or propagate options if the CacheEntry Value was never set. - // We assume an exception occurred causing the caller to not set the Value successfully, - // so don't use this entry. - if (_state.IsValueSet) - { - _cache.SetEntry(this); - - if (_previous != null && CanPropagateOptions()) - { - PropagateOptions(_previous); - } - } - - _previous = null; // we don't want to root unnecessary objects - } - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] // added based on profiling - internal bool CheckExpired(in DateTimeOffset now) - => _state.IsExpired - || CheckForExpiredTime(now) - || (_tokens != null && _tokens.CheckForExpiredTokens(this)); - - internal void SetExpired(EvictionReason reason) - { - if (EvictionReason == EvictionReason.None) - { - EvictionReason = reason; - } - _state.IsExpired = true; - _tokens?.DetachTokens(); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] // added based on profiling - private bool CheckForExpiredTime(in DateTimeOffset now) - { - if (!AbsoluteExpiration.HasValue && !_slidingExpiration.HasValue) - { - return false; - } - - return FullCheck(now); - - bool FullCheck(in DateTimeOffset offset) - { - if (AbsoluteExpiration.HasValue && AbsoluteExpiration.Value <= offset) - { - SetExpired(EvictionReason.Expired); - return true; - } - - if (_slidingExpiration.HasValue - && (offset - LastAccessed) >= _slidingExpiration) - { - SetExpired(EvictionReason.Expired); - return true; - } - - return false; - } - } - - internal void AttachTokens() => _tokens?.AttachTokens(this); - - private static void ExpirationTokensExpired(object obj) - { - // start a new thread to avoid issues with callbacks called from RegisterChangeCallback - Task.Factory.StartNew(state => - { - var entry = (CacheEntry)state; - entry.SetExpired(EvictionReason.TokenExpired); - entry._cache.EntryExpired(entry); - }, obj, CancellationToken.None, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default); - } - - internal void InvokeEvictionCallbacks() => _tokens?.InvokeEvictionCallbacks(this); - - // this simple check very often allows us to avoid expensive call to PropagateOptions(CacheEntryHelper.Current) - [MethodImpl(MethodImplOptions.AggressiveInlining)] // added based on profiling - internal bool CanPropagateOptions() => (_tokens != null && _tokens.CanPropagateTokens()) || AbsoluteExpiration.HasValue; - - internal void PropagateOptions(CacheEntry parent) - { - if (parent == null) - { - return; - } - - // Copy expiration tokens and AbsoluteExpiration to the cache entries hierarchy. - // We do this regardless of it gets cached because the tokens are associated with the value we'll return. - _tokens?.PropagateTokens(parent); - - if (AbsoluteExpiration.HasValue) - { - if (!parent.AbsoluteExpiration.HasValue || AbsoluteExpiration < parent.AbsoluteExpiration) - { - parent.AbsoluteExpiration = AbsoluteExpiration; - } - } - } - - private CacheEntryTokens GetOrCreateTokens() - { - if (_tokens != null) - { - return _tokens; - } - - CacheEntryTokens result = new CacheEntryTokens(); - return Interlocked.CompareExchange(ref _tokens, result, null) ?? result; - } - } -} \ No newline at end of file diff --git a/frameworks/CSharp/appmpower/src/Memory/CacheEntryHelper.cs b/frameworks/CSharp/appmpower/src/Memory/CacheEntryHelper.cs deleted file mode 100644 index 71d07fe24c5..00000000000 --- a/frameworks/CSharp/appmpower/src/Memory/CacheEntryHelper.cs +++ /dev/null @@ -1,32 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System.Diagnostics; -using System.Threading; - -namespace appMpower.Memory -{ - internal static class CacheEntryHelper - { - private static readonly AsyncLocal _current = new AsyncLocal(); - - internal static CacheEntry Current - { - get => _current.Value; - private set => _current.Value = value; - } - - internal static CacheEntry EnterScope(CacheEntry current) - { - CacheEntry previous = Current; - Current = current; - return previous; - } - - internal static void ExitScope(CacheEntry current, CacheEntry previous) - { - Debug.Assert(Current == current, "Entries disposed in invalid order"); - Current = previous; - } - } -} \ No newline at end of file diff --git a/frameworks/CSharp/appmpower/src/Memory/CacheEntryState.cs b/frameworks/CSharp/appmpower/src/Memory/CacheEntryState.cs deleted file mode 100644 index 15d59ead9c1..00000000000 --- a/frameworks/CSharp/appmpower/src/Memory/CacheEntryState.cs +++ /dev/null @@ -1,62 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System; -using Microsoft.Extensions.Caching.Memory; - -namespace appMpower.Memory -{ - internal sealed partial class CacheEntry - { - // this type exists just to reduce CacheEntry size by replacing many enum & boolean fields with one of a size of Int32 - private struct CacheEntryState - { - private byte _flags; - private byte _evictionReason; - private byte _priority; - - internal CacheEntryState(CacheItemPriority priority) : this() => _priority = (byte)priority; - - internal bool IsDisposed - { - get => ((Flags)_flags & Flags.IsDisposed) != 0; - set => SetFlag(Flags.IsDisposed, value); - } - - internal bool IsExpired - { - get => ((Flags)_flags & Flags.IsExpired) != 0; - set => SetFlag(Flags.IsExpired, value); - } - - internal bool IsValueSet - { - get => ((Flags)_flags & Flags.IsValueSet) != 0; - set => SetFlag(Flags.IsValueSet, value); - } - - internal EvictionReason EvictionReason - { - get => (EvictionReason)_evictionReason; - set => _evictionReason = (byte)value; - } - - internal CacheItemPriority Priority - { - get => (CacheItemPriority)_priority; - set => _priority = (byte)value; - } - - private void SetFlag(Flags option, bool value) => _flags = (byte)(value ? (_flags | (byte)option) : (_flags & ~(byte)option)); - - [Flags] - private enum Flags : byte - { - Default = 0, - IsValueSet = 1 << 0, - IsExpired = 1 << 1, - IsDisposed = 1 << 2, - } - } - } -} \ No newline at end of file diff --git a/frameworks/CSharp/appmpower/src/Memory/CacheEntryTokens.cs b/frameworks/CSharp/appmpower/src/Memory/CacheEntryTokens.cs deleted file mode 100644 index 247630639e7..00000000000 --- a/frameworks/CSharp/appmpower/src/Memory/CacheEntryTokens.cs +++ /dev/null @@ -1,140 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System; -using System.Collections.Generic; -using System.Threading; -using System.Threading.Tasks; -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Primitives; -using Microsoft.Extensions.Caching.Memory; - -namespace appMpower.Memory -{ - internal sealed partial class CacheEntry - { - // this type exists just to reduce average CacheEntry size - // which typically is not using expiration tokens or callbacks - private sealed class CacheEntryTokens - { - private List _expirationTokens; - private List _expirationTokenRegistrations; - private List _postEvictionCallbacks; // this is not really related to tokens, but was moved here to shrink typical CacheEntry size - - internal List ExpirationTokens => _expirationTokens ??= new List(); - internal List PostEvictionCallbacks => _postEvictionCallbacks ??= new List(); - - internal void AttachTokens(CacheEntry cacheEntry) - { - if (_expirationTokens != null) - { - lock (this) - { - for (int i = 0; i < _expirationTokens.Count; i++) - { - IChangeToken expirationToken = _expirationTokens[i]; - if (expirationToken.ActiveChangeCallbacks) - { - _expirationTokenRegistrations ??= new List(1); - IDisposable registration = expirationToken.RegisterChangeCallback(ExpirationCallback, cacheEntry); - _expirationTokenRegistrations.Add(registration); - } - } - } - } - } - - internal bool CheckForExpiredTokens(CacheEntry cacheEntry) - { - if (_expirationTokens != null) - { - for (int i = 0; i < _expirationTokens.Count; i++) - { - IChangeToken expiredToken = _expirationTokens[i]; - if (expiredToken.HasChanged) - { - cacheEntry.SetExpired(EvictionReason.TokenExpired); - return true; - } - } - } - return false; - } - - internal bool CanPropagateTokens() => _expirationTokens != null; - - internal void PropagateTokens(CacheEntry parentEntry) - { - if (_expirationTokens != null) - { - lock (this) - { - lock (parentEntry.GetOrCreateTokens()) - { - foreach (IChangeToken expirationToken in _expirationTokens) - { - parentEntry.AddExpirationToken(expirationToken); - } - } - } - } - } - - internal void DetachTokens() - { - // _expirationTokenRegistrations is not checked for null, because AttachTokens might initialize it under lock - // instead we are checking for _expirationTokens, because if they are not null, then _expirationTokenRegistrations might also be not null - if (_expirationTokens != null) - { - lock (this) - { - List registrations = _expirationTokenRegistrations; - if (registrations != null) - { - _expirationTokenRegistrations = null; - for (int i = 0; i < registrations.Count; i++) - { - IDisposable registration = registrations[i]; - registration.Dispose(); - } - } - } - } - } - - internal void InvokeEvictionCallbacks(CacheEntry cacheEntry) - { - if (_postEvictionCallbacks != null) - { - Task.Factory.StartNew(state => InvokeCallbacks((CacheEntry)state), cacheEntry, - CancellationToken.None, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default); - } - } - - private static void InvokeCallbacks(CacheEntry entry) - { - List callbackRegistrations = Interlocked.Exchange(ref entry._tokens._postEvictionCallbacks, null); - - if (callbackRegistrations == null) - { - return; - } - - for (int i = 0; i < callbackRegistrations.Count; i++) - { - PostEvictionCallbackRegistration registration = callbackRegistrations[i]; - - try - { - registration.EvictionCallback?.Invoke(entry.Key, entry.Value, entry.EvictionReason, registration.State); - } - catch (Exception e) - { - // This will be invoked on a background thread, don't let it throw. - entry._cache._logger.LogError(e, "EvictionCallback invoked failed"); - } - } - } - } - } -} \ No newline at end of file diff --git a/frameworks/CSharp/appmpower/src/Memory/MemoryCache.cs b/frameworks/CSharp/appmpower/src/Memory/MemoryCache.cs deleted file mode 100644 index df4f7063cf0..00000000000 --- a/frameworks/CSharp/appmpower/src/Memory/MemoryCache.cs +++ /dev/null @@ -1,520 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System; -using System.Collections.Concurrent; -using System.Collections.Generic; -using System.Runtime.CompilerServices; -using System.Threading; -using System.Threading.Tasks; -using Microsoft.Extensions.Internal; -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Logging.Abstractions; -using Microsoft.Extensions.Options; -using Microsoft.Extensions.Caching.Memory; - -namespace appMpower.Memory -{ - /// - /// An implementation of using a dictionary to - /// store its entries. - /// - public class MemoryCache : IMemoryCache - { - internal readonly ILogger _logger; - - private readonly MemoryCacheOptions _options; - private readonly ConcurrentDictionary _entries; - - private long _cacheSize; - private bool _disposed; - private DateTimeOffset _lastExpirationScan; - - /// - /// Creates a new instance. - /// - /// The options of the cache. - public MemoryCache(IOptions optionsAccessor) - : this(optionsAccessor, NullLoggerFactory.Instance) { } - - /// - /// Creates a new instance. - /// - /// The options of the cache. - /// The factory used to create loggers. - public MemoryCache(IOptions optionsAccessor, ILoggerFactory loggerFactory) - { - if (optionsAccessor == null) - { - throw new ArgumentNullException(nameof(optionsAccessor)); - } - - if (loggerFactory == null) - { - throw new ArgumentNullException(nameof(loggerFactory)); - } - - _options = optionsAccessor.Value; - //_logger = loggerFactory.CreateLogger(); - _logger = loggerFactory.CreateLogger("MemoryCache"); - - _entries = new ConcurrentDictionary(); - - if (_options.Clock == null) - { - _options.Clock = new SystemClock(); - } - - _lastExpirationScan = _options.Clock.UtcNow; - TrackLinkedCacheEntries = _options.TrackLinkedCacheEntries; // we store the setting now so it's consistent for entire MemoryCache lifetime - } - - /// - /// Cleans up the background collection events. - /// - ~MemoryCache() => Dispose(false); - - /// - /// Gets the count of the current entries for diagnostic purposes. - /// - public int Count => _entries.Count; - - // internal for testing - internal long Size { get => Interlocked.Read(ref _cacheSize); } - - internal bool TrackLinkedCacheEntries { get; } - - private ICollection> EntriesCollection => _entries; - - /// - public ICacheEntry CreateEntry(object key) - { - CheckDisposed(); - ValidateCacheKey(key); - - return new CacheEntry(key, this); - } - - internal void SetEntry(CacheEntry entry) - { - if (_disposed) - { - // No-op instead of throwing since this is called during CacheEntry.Dispose - return; - } - - if (_options.SizeLimit.HasValue && !entry.Size.HasValue) - { - //throw new InvalidOperationException(SR.Format(SR.CacheEntryHasEmptySize, nameof(entry.Size), nameof(_options.SizeLimit))); - throw new InvalidOperationException(); - } - - DateTimeOffset utcNow = _options.Clock.UtcNow; - - DateTimeOffset? absoluteExpiration = null; - if (entry.AbsoluteExpirationRelativeToNow.HasValue) - { - absoluteExpiration = utcNow + entry.AbsoluteExpirationRelativeToNow; - } - else if (entry.AbsoluteExpiration.HasValue) - { - absoluteExpiration = entry.AbsoluteExpiration; - } - - // Applying the option's absolute expiration only if it's not already smaller. - // This can be the case if a dependent cache entry has a smaller value, and - // it was set by cascading it to its parent. - if (absoluteExpiration.HasValue) - { - if (!entry.AbsoluteExpiration.HasValue || absoluteExpiration.Value < entry.AbsoluteExpiration.Value) - { - entry.AbsoluteExpiration = absoluteExpiration; - } - } - - // Initialize the last access timestamp at the time the entry is added - entry.LastAccessed = utcNow; - - if (_entries.TryGetValue(entry.Key, out CacheEntry priorEntry)) - { - priorEntry.SetExpired(EvictionReason.Replaced); - } - - bool exceedsCapacity = UpdateCacheSizeExceedsCapacity(entry); - - if (!entry.CheckExpired(utcNow) && !exceedsCapacity) - { - bool entryAdded = false; - - if (priorEntry == null) - { - // Try to add the new entry if no previous entries exist. - entryAdded = _entries.TryAdd(entry.Key, entry); - } - else - { - // Try to update with the new entry if a previous entries exist. - entryAdded = _entries.TryUpdate(entry.Key, entry, priorEntry); - - if (entryAdded) - { - if (_options.SizeLimit.HasValue) - { - // The prior entry was removed, decrease the by the prior entry's size - Interlocked.Add(ref _cacheSize, -priorEntry.Size.Value); - } - } - else - { - // The update will fail if the previous entry was removed after retrival. - // Adding the new entry will succeed only if no entry has been added since. - // This guarantees removing an old entry does not prevent adding a new entry. - entryAdded = _entries.TryAdd(entry.Key, entry); - } - } - - if (entryAdded) - { - entry.AttachTokens(); - } - else - { - if (_options.SizeLimit.HasValue) - { - // Entry could not be added, reset cache size - Interlocked.Add(ref _cacheSize, -entry.Size.Value); - } - entry.SetExpired(EvictionReason.Replaced); - entry.InvokeEvictionCallbacks(); - } - - if (priorEntry != null) - { - priorEntry.InvokeEvictionCallbacks(); - } - } - else - { - if (exceedsCapacity) - { - // The entry was not added due to overcapacity - entry.SetExpired(EvictionReason.Capacity); - - TriggerOvercapacityCompaction(); - } - else - { - if (_options.SizeLimit.HasValue) - { - // Entry could not be added due to being expired, reset cache size - Interlocked.Add(ref _cacheSize, -entry.Size.Value); - } - } - - entry.InvokeEvictionCallbacks(); - if (priorEntry != null) - { - RemoveEntry(priorEntry); - } - } - - StartScanForExpiredItemsIfNeeded(utcNow); - } - - /// - public bool TryGetValue(object key, out object result) - { - ValidateCacheKey(key); - CheckDisposed(); - - DateTimeOffset utcNow = _options.Clock.UtcNow; - - if (_entries.TryGetValue(key, out CacheEntry entry)) - { - // Check if expired due to expiration tokens, timers, etc. and if so, remove it. - // Allow a stale Replaced value to be returned due to concurrent calls to SetExpired during SetEntry. - if (!entry.CheckExpired(utcNow) || entry.EvictionReason == EvictionReason.Replaced) - { - entry.LastAccessed = utcNow; - result = entry.Value; - - if (TrackLinkedCacheEntries && entry.CanPropagateOptions()) - { - // When this entry is retrieved in the scope of creating another entry, - // that entry needs a copy of these expiration tokens. - entry.PropagateOptions(CacheEntryHelper.Current); - } - - StartScanForExpiredItemsIfNeeded(utcNow); - - return true; - } - else - { - // TODO: For efficiency queue this up for batch removal - RemoveEntry(entry); - } - } - - StartScanForExpiredItemsIfNeeded(utcNow); - - result = null; - return false; - } - - /// - public void Remove(object key) - { - ValidateCacheKey(key); - - CheckDisposed(); - if (_entries.TryRemove(key, out CacheEntry entry)) - { - if (_options.SizeLimit.HasValue) - { - Interlocked.Add(ref _cacheSize, -entry.Size.Value); - } - - entry.SetExpired(EvictionReason.Removed); - entry.InvokeEvictionCallbacks(); - } - - StartScanForExpiredItemsIfNeeded(_options.Clock.UtcNow); - } - - private void RemoveEntry(CacheEntry entry) - { - if (EntriesCollection.Remove(new KeyValuePair(entry.Key, entry))) - { - if (_options.SizeLimit.HasValue) - { - Interlocked.Add(ref _cacheSize, -entry.Size.Value); - } - entry.InvokeEvictionCallbacks(); - } - } - - internal void EntryExpired(CacheEntry entry) - { - // TODO: For efficiency consider processing these expirations in batches. - RemoveEntry(entry); - StartScanForExpiredItemsIfNeeded(_options.Clock.UtcNow); - } - - // Called by multiple actions to see how long it's been since we last checked for expired items. - // If sufficient time has elapsed then a scan is initiated on a background task. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private void StartScanForExpiredItemsIfNeeded(DateTimeOffset utcNow) - { - if (_options.ExpirationScanFrequency < utcNow - _lastExpirationScan) - { - ScheduleTask(utcNow); - } - - void ScheduleTask(DateTimeOffset utcNow) - { - _lastExpirationScan = utcNow; - Task.Factory.StartNew(state => ScanForExpiredItems((MemoryCache)state), this, - CancellationToken.None, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default); - } - } - - private static void ScanForExpiredItems(MemoryCache cache) - { - DateTimeOffset now = cache._lastExpirationScan = cache._options.Clock.UtcNow; - - foreach (KeyValuePair item in cache._entries) - { - CacheEntry entry = item.Value; - - if (entry.CheckExpired(now)) - { - cache.RemoveEntry(entry); - } - } - } - - private bool UpdateCacheSizeExceedsCapacity(CacheEntry entry) - { - if (!_options.SizeLimit.HasValue) - { - return false; - } - - long newSize = 0L; - for (int i = 0; i < 100; i++) - { - long sizeRead = Interlocked.Read(ref _cacheSize); - newSize = sizeRead + entry.Size.Value; - - if (newSize < 0 || newSize > _options.SizeLimit) - { - // Overflow occurred, return true without updating the cache size - return true; - } - - if (sizeRead == Interlocked.CompareExchange(ref _cacheSize, newSize, sizeRead)) - { - return false; - } - } - - return true; - } - - private void TriggerOvercapacityCompaction() - { - _logger.LogDebug("Overcapacity compaction triggered"); - - // Spawn background thread for compaction - ThreadPool.QueueUserWorkItem(s => OvercapacityCompaction((MemoryCache)s), this); - } - - private static void OvercapacityCompaction(MemoryCache cache) - { - long currentSize = Interlocked.Read(ref cache._cacheSize); - - cache._logger.LogDebug($"Overcapacity compaction executing. Current size {currentSize}"); - - double? lowWatermark = cache._options.SizeLimit * (1 - cache._options.CompactionPercentage); - if (currentSize > lowWatermark) - { - cache.Compact(currentSize - (long)lowWatermark, entry => entry.Size.Value); - } - - cache._logger.LogDebug($"Overcapacity compaction executed. New size {Interlocked.Read(ref cache._cacheSize)}"); - } - - /// Remove at least the given percentage (0.10 for 10%) of the total entries (or estimated memory?), according to the following policy: - /// 1. Remove all expired items. - /// 2. Bucket by CacheItemPriority. - /// 3. Least recently used objects. - /// ?. Items with the soonest absolute expiration. - /// ?. Items with the soonest sliding expiration. - /// ?. Larger objects - estimated by object graph size, inaccurate. - public void Compact(double percentage) - { - int removalCountTarget = (int)(_entries.Count * percentage); - Compact(removalCountTarget, _ => 1); - } - - private void Compact(long removalSizeTarget, Func computeEntrySize) - { - var entriesToRemove = new List(); - var lowPriEntries = new List(); - var normalPriEntries = new List(); - var highPriEntries = new List(); - long removedSize = 0; - - // Sort items by expired & priority status - DateTimeOffset now = _options.Clock.UtcNow; - foreach (KeyValuePair item in _entries) - { - CacheEntry entry = item.Value; - if (entry.CheckExpired(now)) - { - entriesToRemove.Add(entry); - removedSize += computeEntrySize(entry); - } - else - { - switch (entry.Priority) - { - case CacheItemPriority.Low: - lowPriEntries.Add(entry); - break; - case CacheItemPriority.Normal: - normalPriEntries.Add(entry); - break; - case CacheItemPriority.High: - highPriEntries.Add(entry); - break; - case CacheItemPriority.NeverRemove: - break; - default: - throw new NotSupportedException("Not implemented: " + entry.Priority); - } - } - } - - ExpirePriorityBucket(ref removedSize, removalSizeTarget, computeEntrySize, entriesToRemove, lowPriEntries); - ExpirePriorityBucket(ref removedSize, removalSizeTarget, computeEntrySize, entriesToRemove, normalPriEntries); - ExpirePriorityBucket(ref removedSize, removalSizeTarget, computeEntrySize, entriesToRemove, highPriEntries); - - foreach (CacheEntry entry in entriesToRemove) - { - RemoveEntry(entry); - } - - // Policy: - // 1. Least recently used objects. - // ?. Items with the soonest absolute expiration. - // ?. Items with the soonest sliding expiration. - // ?. Larger objects - estimated by object graph size, inaccurate. - static void ExpirePriorityBucket(ref long removedSize, long removalSizeTarget, Func computeEntrySize, List entriesToRemove, List priorityEntries) - { - // Do we meet our quota by just removing expired entries? - if (removalSizeTarget <= removedSize) - { - // No-op, we've met quota - return; - } - - // Expire enough entries to reach our goal - // TODO: Refine policy - - // LRU - priorityEntries.Sort((e1, e2) => e1.LastAccessed.CompareTo(e2.LastAccessed)); - foreach (CacheEntry entry in priorityEntries) - { - entry.SetExpired(EvictionReason.Capacity); - entriesToRemove.Add(entry); - removedSize += computeEntrySize(entry); - - if (removalSizeTarget <= removedSize) - { - break; - } - } - } - } - - public void Dispose() - { - Dispose(true); - } - - protected virtual void Dispose(bool disposing) - { - if (!_disposed) - { - if (disposing) - { - GC.SuppressFinalize(this); - } - - _disposed = true; - } - } - - private void CheckDisposed() - { - if (_disposed) - { - Throw(); - } - - static void Throw() => throw new ObjectDisposedException(typeof(MemoryCache).FullName); - } - - private static void ValidateCacheKey(object key) - { - if (key == null) - { - Throw(); - } - - static void Throw() => throw new ArgumentNullException(nameof(key)); - } - } -} \ No newline at end of file diff --git a/frameworks/CSharp/appmpower/src/Memory/MemoryCacheOptions.cs b/frameworks/CSharp/appmpower/src/Memory/MemoryCacheOptions.cs deleted file mode 100644 index d714c96df42..00000000000 --- a/frameworks/CSharp/appmpower/src/Memory/MemoryCacheOptions.cs +++ /dev/null @@ -1,67 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System; -using Microsoft.Extensions.Internal; -using Microsoft.Extensions.Options; - -namespace appMpower.Memory -{ - public class MemoryCacheOptions : IOptions - { - private long? _sizeLimit; - private double _compactionPercentage = 0.05; - - public ISystemClock Clock { get; set; } - - /// - /// Gets or sets the minimum length of time between successive scans for expired items. - /// - public TimeSpan ExpirationScanFrequency { get; set; } = TimeSpan.FromMinutes(1); - - /// - /// Gets or sets the maximum size of the cache. - /// - public long? SizeLimit - { - get => _sizeLimit; - set - { - if (value < 0) - { - throw new ArgumentOutOfRangeException(nameof(value), value, $"{nameof(value)} must be non-negative."); - } - - _sizeLimit = value; - } - } - - /// - /// Gets or sets the amount to compact the cache by when the maximum size is exceeded. - /// - public double CompactionPercentage - { - get => _compactionPercentage; - set - { - if (value < 0 || value > 1) - { - throw new ArgumentOutOfRangeException(nameof(value), value, $"{nameof(value)} must be between 0 and 1 inclusive."); - } - - _compactionPercentage = value; - } - } - - /// - /// Gets or sets whether to track linked entries. Disabled by default. - /// - /// Prior to .NET 7 this feature was always enabled. - public bool TrackLinkedCacheEntries { get; set; } - - MemoryCacheOptions IOptions.Value - { - get { return this; } - } - } -} \ No newline at end of file diff --git a/frameworks/CSharp/appmpower/src/Microsoft/CachKey.cs b/frameworks/CSharp/appmpower/src/Microsoft/CachKey.cs deleted file mode 100644 index 3bc21736c08..00000000000 --- a/frameworks/CSharp/appmpower/src/Microsoft/CachKey.cs +++ /dev/null @@ -1,24 +0,0 @@ -using System; - -namespace PlatformBenchmarks -{ - public sealed class CacheKey : IEquatable - { - private readonly int _value; - - public CacheKey(int value) - => _value = value; - - public bool Equals(CacheKey key) - => key._value == _value; - - public override bool Equals(object obj) - => ReferenceEquals(obj, this); - - public override int GetHashCode() - => _value; - - public override string ToString() - => _value.ToString(); - } -} \ No newline at end of file diff --git a/frameworks/CSharp/appmpower/src/Microsoft/StringBuilderCache.cs b/frameworks/CSharp/appmpower/src/Microsoft/StringBuilderCache.cs deleted file mode 100644 index 6f0b20b7278..00000000000 --- a/frameworks/CSharp/appmpower/src/Microsoft/StringBuilderCache.cs +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using System.Text; - -namespace PlatformBenchmarks -{ - internal static class StringBuilderCache - { - private const int DefaultCapacity = 1386; - private const int MaxBuilderSize = DefaultCapacity * 3; - - [ThreadStatic] - private static StringBuilder t_cachedInstance; - - /// Get a StringBuilder for the specified capacity. - /// If a StringBuilder of an appropriate size is cached, it will be returned and the cache emptied. - public static StringBuilder Acquire(int capacity = DefaultCapacity) - { - if (capacity <= MaxBuilderSize) - { - StringBuilder sb = t_cachedInstance; - if (capacity < DefaultCapacity) - { - capacity = DefaultCapacity; - } - - if (sb != null) - { - // Avoid stringbuilder block fragmentation by getting a new StringBuilder - // when the requested size is larger than the current capacity - if (capacity <= sb.Capacity) - { - t_cachedInstance = null; - sb.Clear(); - return sb; - } - } - } - return new StringBuilder(capacity); - } - - public static void Release(StringBuilder sb) - { - if (sb.Capacity <= MaxBuilderSize) - { - t_cachedInstance = sb; - } - } - - public static string GetStringAndRelease(StringBuilder sb) - { - string result = sb.ToString(); - Release(sb); - return result; - } - } -} \ No newline at end of file diff --git a/frameworks/CSharp/appmpower/src/Program.cs b/frameworks/CSharp/appmpower/src/Program.cs deleted file mode 100644 index 6e748b08497..00000000000 --- a/frameworks/CSharp/appmpower/src/Program.cs +++ /dev/null @@ -1,42 +0,0 @@ -using System; -using System.Net; -using System.Threading; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Hosting.Server.Features; -using Microsoft.AspNetCore.Server.Kestrel.Core; -using Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets; -using Microsoft.Extensions.Logging.Abstractions; -using Microsoft.Extensions.Options; - -namespace appMpower -{ - class Program - { - static async Task Main(string[] args) - { - var socketTransportOptions = new SocketTransportOptions(); - var socketTransportFactory = new SocketTransportFactory(Options.Create(socketTransportOptions), NullLoggerFactory.Instance); - var kestrelServerOptions = new KestrelServerOptions(); - - kestrelServerOptions.Listen(IPAddress.Any, 8080); - kestrelServerOptions.AllowSynchronousIO = true; - kestrelServerOptions.AddServerHeader = false; - - using var kestrelServer = new KestrelServer(Options.Create(kestrelServerOptions), socketTransportFactory, NullLoggerFactory.Instance); - - await kestrelServer.StartAsync(new HttpApplication(), CancellationToken.None); - - Console.WriteLine("Listening on:"); - - foreach (var address in kestrelServer.Features.Get().Addresses) - { - Console.WriteLine(" - " + address); - } - - Console.WriteLine("Process CTRL+C to quit"); - var wh = new ManualResetEventSlim(); - Console.CancelKeyPress += (sender, e) => wh.Set(); - wh.Wait(); - } - } -} \ No newline at end of file diff --git a/frameworks/CSharp/appmpower/src/RawDb.cs b/frameworks/CSharp/appmpower/src/RawDb.cs deleted file mode 100644 index 8813ce6dfcc..00000000000 --- a/frameworks/CSharp/appmpower/src/RawDb.cs +++ /dev/null @@ -1,331 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Data; -using System.Linq; -using System.Threading.Tasks; -using Microsoft.Extensions.Caching.Memory; -using appMpower.Data; -using PlatformBenchmarks; - -namespace appMpower -{ - public static class RawDb - { - private const int MaxBatch = 500; - -#if ADO - private static ConcurrentRandom _random = new ConcurrentRandom(); -#else - private static Random _random = new Random(); -#endif - - private static string[] _queriesMultipleRows = new string[MaxBatch + 1]; - - private static readonly object[] _cacheKeys = Enumerable.Range(0, 10001).Select((i) => new CacheKey(i)).ToArray(); - - private static readonly appMpower.Memory.MemoryCache _cache = new appMpower.Memory.MemoryCache( - new appMpower.Memory.MemoryCacheOptions() - { - ExpirationScanFrequency = TimeSpan.FromMinutes(60) - }); - - public static async Task LoadSingleQueryRow() - { - using var pooledConnection = new DbConnection(DbProviderFactory.ConnectionString); - await pooledConnection.OpenAsync(); - - var (dbCommand, _) = CreateReadCommand(pooledConnection); - - using (dbCommand) - { - var world = await ReadSingleRow(dbCommand); - - return world; - } - } - - public static async Task LoadMultipleQueriesRows(int count) - { - var worlds = new World[count]; - - using var pooledConnection = new DbConnection(DbProviderFactory.ConnectionString); - await pooledConnection.OpenAsync(); - - var (dbCommand, dbDataParameter) = CreateReadCommand(pooledConnection); - - using (dbCommand) - { - for (int i = 0; i < count; i++) - { - worlds[i] = await ReadSingleRow(dbCommand); - dbDataParameter.Value = _random.Next(1, 10001); - } - } - - return worlds; - } - - public static async Task> LoadFortunesRows() - { - var fortunes = new List(); - - using var pooledConnection = new DbConnection(DbProviderFactory.ConnectionString); - await pooledConnection.OpenAsync(); - - var dbCommand = new DbCommand("SELECT * FROM fortune", pooledConnection); - - using (dbCommand) - { - var dataReader = await dbCommand.ExecuteReaderAsync(CommandBehavior.SingleResult & CommandBehavior.SequentialAccess); - - while (dataReader.Read()) - { - fortunes.Add(new Fortune - ( - id: dataReader.GetInt32(0), -#if MYSQL - //MariaDB ODBC connector does not correctly support Japanese characters in combination with default ADO.NET; - //as a solution we custom read this string - message: ReadColumn(dataReader, 1) -#else - message: dataReader.GetString(1) -#endif - )); - } - - dataReader.Close(); - } - - fortunes.Add(new Fortune(id: 0, message: "Additional fortune added at request time.")); - fortunes.Sort(); - - return fortunes; - } - - public static async Task LoadMultipleUpdatesRows(int count) - { - var worlds = new World[count]; - - using var pooledConnection = new DbConnection(DbProviderFactory.ConnectionString); - await pooledConnection.OpenAsync(); - - var (queryCommand, dbDataParameter) = CreateReadCommand(pooledConnection); - - using (queryCommand) - { - for (int i = 0; i < count; i++) - { - worlds[i] = await ReadSingleRow(queryCommand); - dbDataParameter.Value = _random.Next(1, 10001); - } - } - - using var updateCommand = new DbCommand(PlatformBenchmarks.BatchUpdateString.Query(count), pooledConnection); - - var ids = PlatformBenchmarks.BatchUpdateString.Ids; - var randoms = PlatformBenchmarks.BatchUpdateString.Randoms; - -#if !MYSQL - var jds = PlatformBenchmarks.BatchUpdateString.Jds; -#endif - - for (int i = 0; i < count; i++) - { - var randomNumber = _random.Next(1, 10001); - - updateCommand.CreateParameter(ids[i], DbType.Int32, worlds[i].Id); - updateCommand.CreateParameter(randoms[i], DbType.Int32, randomNumber); - - worlds[i].RandomNumber = randomNumber; - } - -#if !MYSQL - for (int i = 0; i < count; i++) - { - updateCommand.CreateParameter(jds[i], DbType.Int32, worlds[i].Id); - } -#endif - - await updateCommand.ExecuteNonQueryAsync(); - - return worlds; - } - - private static (DbCommand dbCommand, IDbDataParameter dbDataParameter) CreateReadCommand(DbConnection pooledConnection) - { -#if ADO - var dbCommand = new DbCommand("SELECT * FROM world WHERE id=@Id", pooledConnection); -#else - var dbCommand = new DbCommand("SELECT * FROM world WHERE id=?", pooledConnection); -#endif - - return (dbCommand, dbCommand.CreateParameter("Id", DbType.Int32, _random.Next(1, 10001))); - } - - private static async Task ReadSingleRow(DbCommand dbCommand) - { - var dataReader = await dbCommand.ExecuteReaderAsync(CommandBehavior.SingleRow & CommandBehavior.SequentialAccess); - - dataReader.Read(); - - var world = new World - { - Id = dataReader.GetInt32(0), - RandomNumber = dataReader.GetInt32(1) - }; - - dataReader.Close(); - - return world; - } - - public static async Task ReadMultipleRows(int count) - { - int j = 0; - var ids = PlatformBenchmarks.BatchUpdateString.Ids; - var worlds = new World[count]; - string queryString; - - if (_queriesMultipleRows[count] != null) - { - queryString = _queriesMultipleRows[count]; - } - else - { - var stringBuilder = PlatformBenchmarks.StringBuilderCache.Acquire(); - - for (int i = 0; i < count; i++) - { - stringBuilder.Append("SELECT * FROM world WHERE id=?;"); - } - - queryString = _queriesMultipleRows[count] = PlatformBenchmarks.StringBuilderCache.GetStringAndRelease(stringBuilder); - } - - using var pooledConnection = new DbConnection(DbProviderFactory.ConnectionString); - await pooledConnection.OpenAsync(); - - using var dbCommand = new DbCommand(queryString, pooledConnection); - - for (int i = 0; i < count; i++) - { - dbCommand.CreateParameter(ids[i], DbType.Int32, _random.Next(1, 10001)); - } - - var dataReader = await dbCommand.ExecuteReaderAsync(CommandBehavior.Default & CommandBehavior.SequentialAccess); - - do - { - dataReader.Read(); - - worlds[j] = new World - { - Id = dataReader.GetInt32(0), - RandomNumber = dataReader.GetInt32(1) - }; - - j++; - } while (await dataReader.NextResultAsync()); - - dataReader.Close(); - - return worlds; - } - - public static string ReadColumn(IDataReader dataReader, int column) - { - long size = dataReader.GetBytes(column, 0, null, 0, 0); //get the length of data - byte[] values = new byte[size]; - - int bufferSize = 64; - long bytesRead = 0; - int currentPosition = 0; - - while (bytesRead < size) - { - bytesRead += dataReader.GetBytes(column, currentPosition, values, currentPosition, bufferSize); - currentPosition += bufferSize; - } - - return System.Text.Encoding.Default.GetString(values); - } - - public static async Task PopulateCache() - { - using var pooledConnection = new DbConnection(DbProviderFactory.ConnectionString); - await pooledConnection.OpenAsync(); - - var (dbCommand, dbDataParameter) = CreateReadCommand(pooledConnection); - - using (dbCommand) - { - var cacheKeys = _cacheKeys; - var cache = _cache; - - for (var i = 1; i < 10001; i++) - { - dbDataParameter.Value = i; - cache.Set(cacheKeys[i], await ReadSingleRow(dbCommand)); - } - } - } - - public static Task LoadCachedQueries(int count) - { - var result = new CachedWorld[count]; - var cacheKeys = _cacheKeys; - var cache = _cache; - var random = _random; - - for (var i = 0; i < result.Length; i++) - { - var id = random.Next(1, 10001); - var key = cacheKeys[id]; - - if (cache.TryGetValue(key, out object cached)) - { - result[i] = (CachedWorld)cached; - } - else - { - //return LoadUncachedQueries(id, i, count, this, result); - return LoadUncachedQueries(id, i, count, result); - } - } - - return Task.FromResult(result); - } - - static async Task LoadUncachedQueries(int id, int i, int count, CachedWorld[] result) - { - using var pooledConnection = new DbConnection(DbProviderFactory.ConnectionString); - await pooledConnection.OpenAsync(); - - var (dbCommand, dbDataParameter) = CreateReadCommand(pooledConnection); - - using (dbCommand) - { - Func> create = async (entry) => - { - return await ReadSingleRow(dbCommand); - }; - - var cacheKeys = _cacheKeys; - var key = cacheKeys[id]; - - dbDataParameter.Value = id; - - for (; i < result.Length; i++) - { - result[i] = await _cache.GetOrCreateAsync(key, create); - - id = _random.Next(1, 10001); - dbDataParameter.Value = id; - key = cacheKeys[id]; - } - } - - return result; - } - } -} \ No newline at end of file diff --git a/frameworks/CSharp/appmpower/src/appMpower.Orm/Constants.cs b/frameworks/CSharp/appmpower/src/appMpower.Orm/Constants.cs new file mode 100644 index 00000000000..c1678a71a62 --- /dev/null +++ b/frameworks/CSharp/appmpower/src/appMpower.Orm/Constants.cs @@ -0,0 +1,10 @@ +using appMpower.Orm.Data; + +namespace appMpower.Orm +{ + public static class Constants + { + public static Dbms Dbms = Dbms.PostgreSQL; + public static DbProvider DbProvider = DbProvider.ODBC; + } +} \ No newline at end of file diff --git a/frameworks/CSharp/appmpower/src/Data/DbCommand.cs b/frameworks/CSharp/appmpower/src/appMpower.Orm/Data/DbCommand.cs similarity index 52% rename from frameworks/CSharp/appmpower/src/Data/DbCommand.cs rename to frameworks/CSharp/appmpower/src/appMpower.Orm/Data/DbCommand.cs index 2086068c802..a580aa5e110 100644 --- a/frameworks/CSharp/appmpower/src/Data/DbCommand.cs +++ b/frameworks/CSharp/appmpower/src/appMpower.Orm/Data/DbCommand.cs @@ -1,56 +1,46 @@ using System.Data; -using System.Threading.Tasks; +using System.Data.Odbc; -namespace appMpower.Data +namespace appMpower.Orm.Data { public class DbCommand : IDbCommand { - private IDbCommand _dbCommand; + private OdbcCommand _odbcCommand; private DbConnection _dbConnection; public DbCommand(DbConnection dbConnection) { - _dbCommand = dbConnection.CreateCommand(); + _odbcCommand = (OdbcCommand)dbConnection.CreateCommand(); _dbConnection = dbConnection; } public DbCommand(string commandText, DbConnection dbConnection) { - dbConnection.GetCommand(commandText, CommandType.Text, this); - } - - public DbCommand(string commandText, CommandType commandType, DbConnection dbConnection) - { - dbConnection.GetCommand(commandText, commandType, this); + _odbcCommand = dbConnection.GetCommand(commandText, CommandType.Text); + _dbConnection = dbConnection; } - internal DbCommand(IDbCommand dbCommand, DbConnection dbConnection) + public DbCommand(string commandText, DbConnection dbConnection, bool keyed) { - _dbCommand = dbCommand; + _odbcCommand = dbConnection.GetCommand(commandText, CommandType.Text, keyed); _dbConnection = dbConnection; } - internal IDbCommand Command + public DbCommand(string commandText, CommandType commandType, DbConnection dbConnection) { - get - { - return _dbCommand; - } - set - { - _dbCommand = value; - } + _odbcCommand = dbConnection.GetCommand(commandText, commandType); + _dbConnection = dbConnection; } - internal DbConnection DbConnection + internal IDbCommand Command { get { - return _dbConnection; + return _odbcCommand; } set { - _dbConnection = value; + _odbcCommand = (OdbcCommand)value; } } @@ -58,11 +48,11 @@ public string CommandText { get { - return _dbCommand.CommandText; + return _odbcCommand.CommandText; } set { - _dbCommand.CommandText = value; + _odbcCommand.CommandText = value; } } @@ -70,22 +60,22 @@ public int CommandTimeout { get { - return _dbCommand.CommandTimeout; + return _odbcCommand.CommandTimeout; } set { - _dbCommand.CommandTimeout = value; + _odbcCommand.CommandTimeout = value; } } public CommandType CommandType { get { - return _dbCommand.CommandType; + return _odbcCommand.CommandType; } set { - _dbCommand.CommandType = value; + _odbcCommand.CommandType = value; } } @@ -94,11 +84,11 @@ public IDbConnection? Connection { get { - return _dbCommand.Connection; + return _odbcCommand.Connection; } set { - _dbCommand.Connection = (IDbConnection?)value; + _odbcCommand.Connection = (OdbcConnection?)value; } } #nullable disable @@ -107,7 +97,7 @@ public IDataParameterCollection Parameters { get { - return _dbCommand.Parameters; + return _odbcCommand.Parameters; } } @@ -116,11 +106,11 @@ public IDbTransaction? Transaction { get { - return _dbCommand.Transaction; + return _odbcCommand.Transaction; } set { - _dbCommand.Transaction = (IDbTransaction?)value; + _odbcCommand.Transaction = (OdbcTransaction?)value; } } #nullable disable @@ -129,21 +119,21 @@ public UpdateRowSource UpdatedRowSource { get { - return _dbCommand.UpdatedRowSource; + return _odbcCommand.UpdatedRowSource; } set { - _dbCommand.UpdatedRowSource = value; + _odbcCommand.UpdatedRowSource = value; } } public void Cancel() { - _dbCommand.Cancel(); + _odbcCommand.Cancel(); } public IDbDataParameter CreateParameter() { - return _dbCommand.CreateParameter(); + return _odbcCommand.CreateParameter(); } public IDbDataParameter CreateParameter(string name, object value) @@ -153,21 +143,21 @@ public IDbDataParameter CreateParameter(string name, object value) public IDbDataParameter CreateParameter(string name, DbType dbType, object value) { - IDbDataParameter dbDataParameter = null; + IDbDataParameter dbDataParameter; - if (this.Parameters.Contains(name)) + if (_odbcCommand.Parameters.Contains(name)) { - dbDataParameter = this.Parameters[name] as IDbDataParameter; + dbDataParameter = _odbcCommand.Parameters[name]; dbDataParameter.Value = value; } else { - dbDataParameter = _dbCommand.CreateParameter(); + dbDataParameter = _odbcCommand.CreateParameter(); dbDataParameter.ParameterName = name; dbDataParameter.DbType = dbType; dbDataParameter.Value = value; - this.Parameters.Add(dbDataParameter); + _odbcCommand.Parameters.Add(dbDataParameter); } return dbDataParameter; @@ -175,51 +165,40 @@ public IDbDataParameter CreateParameter(string name, DbType dbType, object value public int ExecuteNonQuery() { - return _dbCommand.ExecuteNonQuery(); + return _odbcCommand.ExecuteNonQuery(); } public IDataReader ExecuteReader() { - return _dbCommand.ExecuteReader(); + return _odbcCommand.ExecuteReader(); } public async Task ExecuteNonQueryAsync() { - return await (_dbCommand as System.Data.Common.DbCommand).ExecuteNonQueryAsync(); - } - - public async Task ExecuteReaderAsync(CommandBehavior behavior) - { - return await (_dbCommand as System.Data.Common.DbCommand).ExecuteReaderAsync(behavior); + return await (_odbcCommand as System.Data.Common.DbCommand).ExecuteNonQueryAsync(); } public IDataReader ExecuteReader(CommandBehavior behavior) { - return _dbCommand.ExecuteReader(behavior); + return _odbcCommand.ExecuteReader(behavior); } #nullable enable public object? ExecuteScalar() { - return _dbCommand.ExecuteScalar(); - } -#nullable disable - -#nullable enable - public async Task ExecuteScalarAsync() - { - return await ((System.Data.Common.DbCommand)_dbCommand).ExecuteScalarAsync(); + return _odbcCommand.ExecuteScalar(); } #nullable disable public void Prepare() { - _dbCommand.Prepare(); + _odbcCommand.Prepare(); } public void Dispose() { - _dbConnection.ReleaseCommand(this); + if (_dbConnection._keyed) _dbConnection._keyedOdbcCommands.TryAdd(_odbcCommand.CommandText, _odbcCommand); + else _dbConnection._odbcCommands.Push(_odbcCommand); } } } \ No newline at end of file diff --git a/frameworks/CSharp/appmpower/src/appMpower.Orm/Data/DbConnection.cs b/frameworks/CSharp/appmpower/src/appMpower.Orm/Data/DbConnection.cs new file mode 100644 index 00000000000..ba3b6cf85b6 --- /dev/null +++ b/frameworks/CSharp/appmpower/src/appMpower.Orm/Data/DbConnection.cs @@ -0,0 +1,153 @@ +using System.Collections.Concurrent; +using System.Data; +using System.Data.Odbc; + +namespace appMpower.Orm.Data +{ + public class DbConnection : IDbConnection + { + private string _connectionString; + internal bool _keyed = false; + internal int _number; + internal OdbcConnection _odbcConnection; + internal ConcurrentStack _odbcCommands = new(); + internal Dictionary _keyedOdbcCommands; + + public DbConnection() + { + _connectionString = DbProviderFactory.ConnectionString; + } + + public DbConnection(string connectionString) + { + _connectionString = connectionString; + } + + public IDbConnection Connection + { + get + { + return _odbcConnection; + } + set + { + _odbcConnection = (OdbcConnection)value; + } + } + + public string ConnectionString + { + get + { + return _odbcConnection.ConnectionString; + } + set + { + _odbcConnection.ConnectionString = value; + } + } + + public int ConnectionTimeout + { + get + { + return _odbcConnection.ConnectionTimeout; + } + } + + public string Database + { + get + { + return _odbcConnection.Database; + } + } + + public ConnectionState State + { + get + { + if (_odbcConnection is null) return ConnectionState.Closed; + return _odbcConnection.State; + } + } + + public IDbTransaction BeginTransaction() + { + return _odbcConnection.BeginTransaction(); + } + + public IDbTransaction BeginTransaction(IsolationLevel il) + { + return _odbcConnection.BeginTransaction(il); + } + + public void ChangeDatabase(string databaseName) + { + _odbcConnection.ChangeDatabase(databaseName); + } + + public void Close() + { + _odbcConnection.Close(); + } + + public IDbCommand CreateCommand() + { + return _odbcConnection.CreateCommand(); + } + + public void Open() + { + if (_odbcConnection is null) + { + DbConnections.GetConnection(_connectionString, this); + } + + if (_odbcConnection.State == ConnectionState.Closed) + { + _odbcConnection.Open(); + } + } + + public void Dispose() + { + DbConnections.Release(this); + } + + internal OdbcCommand GetCommand(string commandText, CommandType commandType, bool keyed = false) + { + OdbcCommand odbcCommand; + + if (_odbcCommands.TryPop(out odbcCommand)) + { + if (commandText != odbcCommand.CommandText) + { + odbcCommand.CommandText = commandText; + odbcCommand.Parameters.Clear(); + } + + return odbcCommand; + } + else if (_keyed && _keyedOdbcCommands.TryGetValue(commandText, out odbcCommand)) + { + return odbcCommand; + } + else + { + if (!_keyed && keyed) + { + _keyedOdbcCommands = new(); + _keyed = keyed; + } + + odbcCommand = _odbcConnection.CreateCommand(); + odbcCommand.CommandText = commandText; + odbcCommand.CommandType = commandType; + odbcCommand.Prepare(); + + return odbcCommand; + } + } + } +} \ No newline at end of file diff --git a/frameworks/CSharp/appmpower/src/appMpower.Orm/Data/DbConnections.cs b/frameworks/CSharp/appmpower/src/appMpower.Orm/Data/DbConnections.cs new file mode 100644 index 00000000000..514e2945d38 --- /dev/null +++ b/frameworks/CSharp/appmpower/src/appMpower.Orm/Data/DbConnections.cs @@ -0,0 +1,61 @@ +using System.Collections.Concurrent; + +namespace appMpower.Orm.Data +{ + public static class DbConnections + { + private static short _createdConnections = 0; + private static ConcurrentStack _connectionsStack = new(); + + public static DbConnection GetConnection(string connectionString) + { + DbConnection popDbConnection; + + if (!_connectionsStack.TryPop(out popDbConnection)) + { + popDbConnection = new DbConnection(); + popDbConnection._odbcConnection = new System.Data.Odbc.OdbcConnection(connectionString); + + _createdConnections++; + popDbConnection._number = _createdConnections; + + if (_createdConnections % 25 == 0) + { + Console.WriteLine("Pooled connections created: " + _createdConnections.ToString()); + } + } + + return popDbConnection; + } + + + public static void GetConnection(string connectionString, DbConnection dbConnection) + { + DbConnection popDbConnection = null; + + if (_connectionsStack.TryPop(out popDbConnection)) + { + dbConnection._odbcConnection = popDbConnection._odbcConnection; + dbConnection._odbcCommands = popDbConnection._odbcCommands; + dbConnection._number = popDbConnection._number; + } + else + { + dbConnection._odbcConnection = new System.Data.Odbc.OdbcConnection(connectionString); + + _createdConnections++; + dbConnection._number = _createdConnections; + + if (_createdConnections % 25 == 0) + { + Console.WriteLine("Pooled connections created: " + _createdConnections.ToString()); + } + } + } + + public static void Release(DbConnection dbConnection) + { + _connectionsStack.Push(dbConnection); + } + } +} \ No newline at end of file diff --git a/frameworks/CSharp/appmpower/src/appMpower.Orm/Data/DbProvider.cs b/frameworks/CSharp/appmpower/src/appMpower.Orm/Data/DbProvider.cs new file mode 100644 index 00000000000..bf60750b52d --- /dev/null +++ b/frameworks/CSharp/appmpower/src/appMpower.Orm/Data/DbProvider.cs @@ -0,0 +1,8 @@ +namespace appMpower.Orm.Data +{ + public enum DbProvider + { + ADO = 0, + ODBC = 1, + } +} \ No newline at end of file diff --git a/frameworks/CSharp/appmpower/src/appMpower.Orm/Data/DbProviderFactory.cs b/frameworks/CSharp/appmpower/src/appMpower.Orm/Data/DbProviderFactory.cs new file mode 100644 index 00000000000..1e72d164a25 --- /dev/null +++ b/frameworks/CSharp/appmpower/src/appMpower.Orm/Data/DbProviderFactory.cs @@ -0,0 +1,21 @@ +using System.Data; + +namespace appMpower.Orm.Data +{ + public static class DbProviderFactory + { + public static string ConnectionString; + + public static void SetConnectionString() + { + if (Constants.Dbms == Dbms.MySQL) + { + ConnectionString = "Driver={MariaDB};Server=tfb-database;Database=hello_world;Uid=benchmarkdbuser;Pwd=benchmarkdbpass;Pooling=false;OPTIONS=67108864;FLAG_FORWARD_CURSOR=1;sslmode=DISABLED;CharSet=utf8;"; + } + else + { + ConnectionString = "Driver={PostgreSQL};Server=tfb-database;Database=hello_world;Uid=benchmarkdbuser;Pwd=benchmarkdbpass;UseServerSidePrepare=1;Pooling=false;sslmode=disable"; + } + } + } +} \ No newline at end of file diff --git a/frameworks/CSharp/appmpower/src/appMpower.Orm/Data/Dbms.cs b/frameworks/CSharp/appmpower/src/appMpower.Orm/Data/Dbms.cs new file mode 100644 index 00000000000..8c8bbeb67e6 --- /dev/null +++ b/frameworks/CSharp/appmpower/src/appMpower.Orm/Data/Dbms.cs @@ -0,0 +1,9 @@ +namespace appMpower.Orm.Data +{ + public enum Dbms + { + MySQL = 0, + PostgreSQL = 1, + SQLServer = 2, + } +} \ No newline at end of file diff --git a/frameworks/CSharp/appmpower/src/appMpower.Orm/DotnetMethods.cs b/frameworks/CSharp/appmpower/src/appMpower.Orm/DotnetMethods.cs new file mode 100644 index 00000000000..f6b8b4cad1c --- /dev/null +++ b/frameworks/CSharp/appmpower/src/appMpower.Orm/DotnetMethods.cs @@ -0,0 +1,66 @@ +using System.Runtime.InteropServices; +using System.Text; +using System.Text.Json; +using appMpower.Orm.Data; +using appMpower.Orm.Objects; +using appMpower.Orm.Serializers; + +namespace appMpower.Orm; + +//These methods are for test purposes only; not used in actual execution +public static class DotnetMethods +{ + private static JsonWriterOptions _jsonWriterOptions = new JsonWriterOptions + { + Indented = false, + SkipValidation = true + }; + + private readonly static WorldSerializer _worldSerializer = new WorldSerializer(); + private readonly static WorldsSerializer _worldsSerializer = new WorldsSerializer(); + + public static byte[] Db() + { + var world = RawDb.LoadSingleQueryRow(); + + var memoryStream = new MemoryStream(); + using var utf8JsonWriter = new Utf8JsonWriter(memoryStream, _jsonWriterOptions); + + _worldSerializer.Serialize(utf8JsonWriter, world); + + return memoryStream.ToArray(); + } + + public static byte[] Query(int queries) + { + World[] worlds = RawDb.ReadMultipleRows(queries); + + var memoryStream = new MemoryStream(); + using var utf8JsonWriter = new Utf8JsonWriter(memoryStream, _jsonWriterOptions); + + _worldsSerializer.Serialize(utf8JsonWriter, worlds); + + return memoryStream.ToArray(); + } + + public static byte[] Updates(int count) + { + World[] worlds = RawDb.LoadMultipleUpdatesRows(count); + + var memoryStream = new MemoryStream(); + using var utf8JsonWriter = new Utf8JsonWriter(memoryStream, _jsonWriterOptions); + + _worldsSerializer.Serialize(utf8JsonWriter, worlds); + + return memoryStream.ToArray(); + } + + public static byte[] Fortunes() + { + List fortunes = RawDb.LoadFortunesRows(); + string fortunesView = FortunesView.Render(fortunes); + byte[] byteArray = Encoding.UTF8.GetBytes(fortunesView); + + return byteArray.ToArray(); + } +} \ No newline at end of file diff --git a/frameworks/CSharp/appmpower/src/FortunesView.cs b/frameworks/CSharp/appmpower/src/appMpower.Orm/FortunesView.cs similarity index 54% rename from frameworks/CSharp/appmpower/src/FortunesView.cs rename to frameworks/CSharp/appmpower/src/appMpower.Orm/FortunesView.cs index 8f56ddde4d5..2c11f6473c6 100644 --- a/frameworks/CSharp/appmpower/src/FortunesView.cs +++ b/frameworks/CSharp/appmpower/src/appMpower.Orm/FortunesView.cs @@ -1,33 +1,23 @@ using System.Collections.Generic; -using System.IO.Pipelines; using System.Globalization; using System.Text; using System.Threading.Tasks; using System.Web; -using Microsoft.AspNetCore.Http; -using Microsoft.Extensions.Primitives; using PlatformBenchmarks; +using appMpower.Orm.Objects; -namespace appMpower +namespace appMpower.Orm { public static class FortunesView { - private readonly static KeyValuePair _headerServer = - new KeyValuePair("Server", "k"); - private readonly static KeyValuePair _headerContentType = - new KeyValuePair("Content-Type", "text/html; charset=UTF-8"); - public static char[] _fortunesTableStart = "Fortunes".ToCharArray(); public static char[] _fortunesRowStart = "".ToCharArray(); public static char[] _fortunesTableEnd = "
idmessage
".ToCharArray(); public static char[] _fortunesColumn = "".ToCharArray(); public static char[] _fortunesRowEnd = "
".ToCharArray(); - public static async Task Render(IHeaderDictionary headerDictionary, PipeWriter pipeWriter, List fortunes) + public static string Render(List fortunes) { - headerDictionary.Add(_headerServer); - headerDictionary.Add(_headerContentType); - var writer = StringBuilderCache.Acquire(); writer.Append(_fortunesTableStart); @@ -39,10 +29,7 @@ public static async Task Render(IHeaderDictionary headerDictionary, PipeWriter p writer.Append(_fortunesTableEnd); - headerDictionary.Add(new KeyValuePair("Content-Length", (writer.Length + 32).ToString())); - - await pipeWriter.WriteAsync(Encoding.UTF8.GetBytes(StringBuilderCache.GetStringAndRelease(writer))); - pipeWriter.Complete(); + return StringBuilderCache.GetStringAndRelease(writer); } } } \ No newline at end of file diff --git a/frameworks/CSharp/appmpower/src/Microsoft/BatchUpdateString.cs b/frameworks/CSharp/appmpower/src/appMpower.Orm/Microsoft/BatchUpdateString.cs similarity index 54% rename from frameworks/CSharp/appmpower/src/Microsoft/BatchUpdateString.cs rename to frameworks/CSharp/appmpower/src/appMpower.Orm/Microsoft/BatchUpdateString.cs index 0f3e501c485..a5887f50142 100644 --- a/frameworks/CSharp/appmpower/src/Microsoft/BatchUpdateString.cs +++ b/frameworks/CSharp/appmpower/src/appMpower.Orm/Microsoft/BatchUpdateString.cs @@ -1,7 +1,8 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. -using System.Linq; +using appMpower.Orm; +using appMpower.Orm.Data; namespace PlatformBenchmarks { @@ -33,51 +34,32 @@ public static string Query(int batchSize) //sb.Append("(?::int,?::int)) AS temp(id, randomNumber) WHERE temp.id = world.id"); */ -#if MYSQL - for (int i = 0; i < batchSize; i++) + if (Constants.Dbms == Dbms.MySQL) { - sb.Append("UPDATE world SET randomNumber=? WHERE id=?;"); + for (int i = 0; i < batchSize; i++) + { + sb.Append("UPDATE world SET randomNumber=? WHERE id=?;"); + } } -#elif ADO - /* - sb.Append("UPDATE world SET randomNumber = temp.randomNumber FROM (VALUES "); - Enumerable.Range(0, lastIndex).ToList().ForEach(i => sb.Append($"(@i{i}, @r{i}), ")); - sb.Append($"(@i{lastIndex}, @r{lastIndex}) ORDER BY 1) AS temp(id, randomNumber) WHERE temp.id = world.id"); - */ - - sb.Append("UPDATE world SET randomNumber=CASE id "); - - for (int i = 0; i < batchSize; i++) - { - sb.Append("WHEN @i" + i + " THEN @r" + i + " "); - } - - sb.Append("ELSE randomnumber END WHERE id IN("); - - for (int i = 0; i < lastIndex; i++) + else { - sb.Append("@j" + i + ","); - } + sb.Append("UPDATE world SET randomNumber=CASE id "); - sb.Append("@j" + lastIndex + ")"); -#else - sb.Append("UPDATE world SET randomNumber=CASE id "); + for (int i = 0; i < batchSize; i++) + { + sb.Append("WHEN ? THEN ? "); + } - for (int i = 0; i < batchSize; i++) - { - sb.Append("WHEN ? THEN ? "); - } + sb.Append("ELSE randomnumber END WHERE id IN("); - sb.Append("ELSE randomnumber END WHERE id IN("); + for (int i = 0; i < lastIndex; i++) + { + sb.Append("?,"); + } - for (int i = 0; i < lastIndex; i++) - { - sb.Append("?,"); + sb.Append("?)"); } - sb.Append("?)"); -#endif - return _queries[batchSize] = StringBuilderCache.GetStringAndRelease(sb); } } diff --git a/frameworks/CSharp/appmpower/src/Microsoft/ConcurrentRandom.cs b/frameworks/CSharp/appmpower/src/appMpower.Orm/Microsoft/ConcurrentRandom.cs similarity index 95% rename from frameworks/CSharp/appmpower/src/Microsoft/ConcurrentRandom.cs rename to frameworks/CSharp/appmpower/src/appMpower.Orm/Microsoft/ConcurrentRandom.cs index b5a74d48884..374c9f4e1bb 100644 --- a/frameworks/CSharp/appmpower/src/Microsoft/ConcurrentRandom.cs +++ b/frameworks/CSharp/appmpower/src/appMpower.Orm/Microsoft/ConcurrentRandom.cs @@ -1,9 +1,7 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. -using System; using System.Runtime.CompilerServices; -using System.Threading; namespace PlatformBenchmarks { diff --git a/frameworks/CSharp/appmpower/src/appMpower.Orm/Microsoft/StringBuilderCache.cs b/frameworks/CSharp/appmpower/src/appMpower.Orm/Microsoft/StringBuilderCache.cs new file mode 100644 index 00000000000..73b890db750 --- /dev/null +++ b/frameworks/CSharp/appmpower/src/appMpower.Orm/Microsoft/StringBuilderCache.cs @@ -0,0 +1,54 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System.Text; + +namespace PlatformBenchmarks; + +internal static class StringBuilderCache +{ + private const int DefaultCapacity = 1386; + private const int MaxBuilderSize = DefaultCapacity * 3; + [ThreadStatic] + private static StringBuilder t_cachedInstance; + + public static StringBuilder Acquire(int capacity = DefaultCapacity) + { + if (capacity <= MaxBuilderSize) + { + StringBuilder sb = t_cachedInstance; + + if (capacity < DefaultCapacity) + { + capacity = DefaultCapacity; + } + + if (sb != null) + { + if (capacity <= sb.Capacity) + { + t_cachedInstance = null; + sb.Clear(); + return sb; + } + } + } + + return new StringBuilder(capacity); + } + + public static void Release(StringBuilder sb) + { + if (sb.Capacity <= MaxBuilderSize) + { + t_cachedInstance = sb; + } + } + + public static string GetStringAndRelease(StringBuilder sb) + { + string result = sb.ToString(); + Release(sb); + return result; + } +} diff --git a/frameworks/CSharp/appmpower/src/appMpower.Orm/NativeMethods.cs b/frameworks/CSharp/appmpower/src/appMpower.Orm/NativeMethods.cs new file mode 100644 index 00000000000..0f3ee5b59c2 --- /dev/null +++ b/frameworks/CSharp/appmpower/src/appMpower.Orm/NativeMethods.cs @@ -0,0 +1,144 @@ +using System.Runtime.InteropServices; +using System.Text; +using System.Text.Json; +using appMpower.Orm.Data; +using appMpower.Orm.Objects; +using appMpower.Orm.Serializers; + +namespace appMpower.Orm; + +public static class NativeMethods +{ + private static JsonWriterOptions _jsonWriterOptions = new JsonWriterOptions + { + Indented = false, + SkipValidation = true + }; + + private readonly static WorldSerializer _worldSerializer = new WorldSerializer(); + private readonly static WorldsSerializer _worldsSerializer = new WorldsSerializer(); + + [UnmanagedCallersOnly(EntryPoint = "Dbms")] + public static void Dbms(int dbms) + { + Constants.Dbms = (Dbms)dbms; + DbProviderFactory.SetConnectionString(); + } + + [UnmanagedCallersOnly(EntryPoint = "DbProvider")] + public static void DbProvider(int dbProvider) + { + Constants.DbProvider = (DbProvider)dbProvider; + DbProviderFactory.SetConnectionString(); + } + + [UnmanagedCallersOnly(EntryPoint = "FreeHandlePointer")] + public static void FreeHandlePointer(IntPtr handlePointer) + { + GCHandle handle = GCHandle.FromIntPtr(handlePointer); + handle.Free(); + } + + [UnmanagedCallersOnly(EntryPoint = "Db")] + public static unsafe IntPtr Db(int* length, IntPtr* handlePointer) + { + var world = RawDb.LoadSingleQueryRow(); + + var memoryStream = new MemoryStream(); + using var utf8JsonWriter = new Utf8JsonWriter(memoryStream, _jsonWriterOptions); + + _worldSerializer.Serialize(utf8JsonWriter, world); + + *length = (int)utf8JsonWriter.BytesCommitted; + byte[] byteArray = memoryStream.ToArray(); + + GCHandle handle = GCHandle.Alloc(byteArray, GCHandleType.Pinned); + // return the managed and byteArrayPointer pointer + IntPtr byteArrayPointer = handle.AddrOfPinnedObject(); + *handlePointer = GCHandle.ToIntPtr(handle); + + return byteArrayPointer; + /* + fixed(byte* b = memoryStream.ToArray()) + { + return b; + } + */ + } + + [UnmanagedCallersOnly(EntryPoint = "Fortunes")] + public static unsafe IntPtr Fortunes(int* length, IntPtr* handlePointer) + { + List fortunes = RawDb.LoadFortunesRows(); + string fortunesView = FortunesView.Render(fortunes); + byte[] byteArray = Encoding.UTF8.GetBytes(fortunesView); + + *length = byteArray.Length; + + GCHandle handle = GCHandle.Alloc(byteArray, GCHandleType.Pinned); + IntPtr byteArrayPointer = handle.AddrOfPinnedObject(); + *handlePointer = GCHandle.ToIntPtr(handle); + + return byteArrayPointer; + } + + [UnmanagedCallersOnly(EntryPoint = "Query")] + public static unsafe IntPtr Query(int queries, int* length, IntPtr* handlePointer) + { + World[] worlds = RawDb.ReadMultipleRows(queries); + + var memoryStream = new MemoryStream(); + using var utf8JsonWriter = new Utf8JsonWriter(memoryStream, _jsonWriterOptions); + + _worldsSerializer.Serialize(utf8JsonWriter, worlds); + + *length = (int)utf8JsonWriter.BytesCommitted; + byte[] byteArray = memoryStream.ToArray(); + + GCHandle handle = GCHandle.Alloc(byteArray, GCHandleType.Pinned); + IntPtr byteArrayPointer = handle.AddrOfPinnedObject(); + *handlePointer = GCHandle.ToIntPtr(handle); + + return byteArrayPointer; + } + + [UnmanagedCallersOnly(EntryPoint = "Updates")] + public static unsafe IntPtr Updates(int count, int* length, IntPtr* handlePointer) + { + World[] worlds = RawDb.LoadMultipleUpdatesRows(count); + + var memoryStream = new MemoryStream(); + using var utf8JsonWriter = new Utf8JsonWriter(memoryStream, _jsonWriterOptions); + + _worldsSerializer.Serialize(utf8JsonWriter, worlds); + + *length = (int)utf8JsonWriter.BytesCommitted; + byte[] byteArray = memoryStream.ToArray(); + + GCHandle handle = GCHandle.Alloc(byteArray, GCHandleType.Pinned); + IntPtr byteArrayPointer = handle.AddrOfPinnedObject(); + *handlePointer = GCHandle.ToIntPtr(handle); + + return byteArrayPointer; + } + + [UnmanagedCallersOnly(EntryPoint = "DbById")] + public static unsafe IntPtr DbById(int id, int* length, IntPtr* handlePointer) + { + var world = RawDb.LoadSingleQueryRowById(id); + + var memoryStream = new MemoryStream(); + using var utf8JsonWriter = new Utf8JsonWriter(memoryStream, _jsonWriterOptions); + + _worldSerializer.Serialize(utf8JsonWriter, world); + + *length = (int)utf8JsonWriter.BytesCommitted; + byte[] byteArray = memoryStream.ToArray(); + + GCHandle handle = GCHandle.Alloc(byteArray, GCHandleType.Pinned); + IntPtr byteArrayPointer = handle.AddrOfPinnedObject(); + *handlePointer = GCHandle.ToIntPtr(handle); + + return byteArrayPointer; + } +} diff --git a/frameworks/CSharp/appmpower/src/CachedWorld.cs b/frameworks/CSharp/appmpower/src/appMpower.Orm/Objects/CachedWorld.cs similarity index 88% rename from frameworks/CSharp/appmpower/src/CachedWorld.cs rename to frameworks/CSharp/appmpower/src/appMpower.Orm/Objects/CachedWorld.cs index 857b8283c73..7ef3f074167 100644 --- a/frameworks/CSharp/appmpower/src/CachedWorld.cs +++ b/frameworks/CSharp/appmpower/src/appMpower.Orm/Objects/CachedWorld.cs @@ -1,4 +1,4 @@ -namespace appMpower +namespace appMpower.Orm.Objects { public struct CachedWorld { diff --git a/frameworks/CSharp/appmpower/src/Fortune.cs b/frameworks/CSharp/appmpower/src/appMpower.Orm/Objects/Fortune.cs similarity index 93% rename from frameworks/CSharp/appmpower/src/Fortune.cs rename to frameworks/CSharp/appmpower/src/appMpower.Orm/Objects/Fortune.cs index 4d1b99661ca..c6eb823c9fa 100644 --- a/frameworks/CSharp/appmpower/src/Fortune.cs +++ b/frameworks/CSharp/appmpower/src/appMpower.Orm/Objects/Fortune.cs @@ -1,6 +1,4 @@ -using System; - -namespace appMpower +namespace appMpower.Orm.Objects { public readonly struct Fortune : IComparable, IComparable { diff --git a/frameworks/CSharp/appmpower/src/World.cs b/frameworks/CSharp/appmpower/src/appMpower.Orm/Objects/World.cs similarity index 78% rename from frameworks/CSharp/appmpower/src/World.cs rename to frameworks/CSharp/appmpower/src/appMpower.Orm/Objects/World.cs index cfec08b1f9c..4e10e128998 100644 --- a/frameworks/CSharp/appmpower/src/World.cs +++ b/frameworks/CSharp/appmpower/src/appMpower.Orm/Objects/World.cs @@ -1,4 +1,4 @@ -namespace appMpower +namespace appMpower.Orm.Objects { public struct World { diff --git a/frameworks/CSharp/appmpower/src/appMpower.Orm/RawDb.cs b/frameworks/CSharp/appmpower/src/appMpower.Orm/RawDb.cs new file mode 100644 index 00000000000..b748d78a251 --- /dev/null +++ b/frameworks/CSharp/appmpower/src/appMpower.Orm/RawDb.cs @@ -0,0 +1,257 @@ +using System.Data; +using appMpower.Orm.Data; +using appMpower.Orm.Objects; +using PlatformBenchmarks; + +namespace appMpower.Orm +{ + public static class RawDb + { + private const int MaxBatch = 500; + + private static Random _random = new Random(); + + private static string[] _queriesMultipleRows = new string[MaxBatch + 1]; + + public static World LoadSingleQueryRow() + { + using var pooledConnection = DbConnections.GetConnection(DbProviderFactory.ConnectionString); + pooledConnection.Open(); + + var (dbCommand, _) = CreateReadCommand(pooledConnection); + + using (dbCommand) + { + World world = ReadSingleRow(dbCommand); + + return world; + } + } + + public static World LoadSingleQueryRowById(int id) + { + using var pooledConnection = DbConnections.GetConnection(DbProviderFactory.ConnectionString); + pooledConnection.Open(); + + var (dbCommand, _) = CreateReadCommandById(pooledConnection, id); + + using (dbCommand) + { + World world = ReadSingleRow(dbCommand); + + return world; + } + } + + public static World[] LoadMultipleQueriesRows(int count) + { + var worlds = new World[count]; + + using var pooledConnection = DbConnections.GetConnection(DbProviderFactory.ConnectionString); + pooledConnection.Open(); + + var (dbCommand, dbDataParameter) = CreateReadCommand(pooledConnection); + + using (dbCommand) + { + for (int i = 0; i < count; i++) + { + worlds[i] = ReadSingleRow(dbCommand); + dbDataParameter.Value = _random.Next(1, 10001); + } + } + + return worlds; + } + + public static List LoadFortunesRows() + { + var fortunes = new List(); + + using var pooledConnection = DbConnections.GetConnection(DbProviderFactory.ConnectionString); + pooledConnection.Open(); + + var dbCommand = new DbCommand("SELECT * FROM fortune", pooledConnection); + + using (dbCommand) + { + IDataReader dataReader = dbCommand.ExecuteReader(CommandBehavior.SingleResult & CommandBehavior.SequentialAccess); + + while (dataReader.Read()) + { + fortunes.Add(new Fortune + ( + id: dataReader.GetInt32(0), + //MariaDB ODBC connector does not correctly support Japanese characters in combination with default ADO.NET; + //as a solution we custom read this string + message: (Constants.Dbms == Dbms.MySQL ? ReadColumn(dataReader, 1) : dataReader.GetString(1)) + )); + } + + dataReader.Close(); + } + + fortunes.Add(new Fortune(id: 0, message: "Additional fortune added at request time.")); + fortunes.Sort(); + + return fortunes; + } + + public static World[] LoadMultipleUpdatesRows(int count) + { + var worlds = new World[count]; + + using var pooledConnection = DbConnections.GetConnection(DbProviderFactory.ConnectionString); + pooledConnection.Open(); + + var (queryCommand, dbDataParameter) = CreateReadCommand(pooledConnection, true); + + using (queryCommand) + { + for (int i = 0; i < count; i++) + { + worlds[i] = ReadSingleRow(queryCommand); + dbDataParameter.Value = _random.Next(1, 10001); + } + } + + using var updateCommand = new DbCommand(BatchUpdateString.Query(count), pooledConnection, true); + + var ids = BatchUpdateString.Ids; + var randoms = BatchUpdateString.Randoms; + + for (int i = 0; i < count; i++) + { + var randomNumber = _random.Next(1, 10001); + + updateCommand.CreateParameter(ids[i], DbType.Int32, worlds[i].Id); + updateCommand.CreateParameter(randoms[i], DbType.Int32, randomNumber); + + worlds[i].RandomNumber = randomNumber; + } + + if (Constants.Dbms != Dbms.MySQL) + { + var jds = BatchUpdateString.Jds; + + for (int i = 0; i < count; i++) + { + updateCommand.CreateParameter(jds[i], DbType.Int32, worlds[i].Id); + } + } + + updateCommand.ExecuteNonQuery(); + + return worlds; + } + + internal static (DbCommand dbCommand, IDbDataParameter dbDataParameter) CreateReadCommand(DbConnection pooledConnection) + { + DbCommand dbCommand = new DbCommand("SELECT * FROM world WHERE id=?", pooledConnection); + + return (dbCommand, dbCommand.CreateParameter("Id", DbType.Int32, _random.Next(1, 10001))); + } + + internal static (DbCommand dbCommand, IDbDataParameter dbDataParameter) CreateReadCommand(DbConnection pooledConnection, bool keyed) + { + DbCommand dbCommand = new DbCommand("SELECT * FROM world WHERE id=?", pooledConnection, keyed); + + return (dbCommand, dbCommand.CreateParameter("Id", DbType.Int32, _random.Next(1, 10001))); + } + + internal static (DbCommand dbCommand, IDbDataParameter dbDataParameter) CreateReadCommandById(DbConnection pooledConnection, int id) + { + DbCommand dbCommand = new DbCommand("SELECT * FROM world WHERE id=?", pooledConnection); + + return (dbCommand, dbCommand.CreateParameter("Id", DbType.Int32, id)); + } + + internal static World ReadSingleRow(DbCommand dbCommand) + { + var dataReader = dbCommand.ExecuteReader(CommandBehavior.SingleRow & CommandBehavior.SequentialAccess); + + dataReader.Read(); + + var world = new World + { + Id = dataReader.GetInt32(0), + RandomNumber = dataReader.GetInt32(1) + }; + + dataReader.Close(); + + return world; + } + + public static World[] ReadMultipleRows(int count) + { + int j = 0; + var ids = BatchUpdateString.Ids; + var worlds = new World[count]; + string queryString; + + if (_queriesMultipleRows[count] != null) + { + queryString = _queriesMultipleRows[count]; + } + else + { + var stringBuilder = StringBuilderCache.Acquire(); + + for (int i = 0; i < count; i++) + { + stringBuilder.Append("SELECT * FROM world WHERE id=?;"); + } + + queryString = _queriesMultipleRows[count] = StringBuilderCache.GetStringAndRelease(stringBuilder); + } + + using var pooledConnection = DbConnections.GetConnection(DbProviderFactory.ConnectionString); + pooledConnection.Open(); + + using var dbCommand = new DbCommand(queryString, pooledConnection); + + for (int i = 0; i < count; i++) + { + dbCommand.CreateParameter(ids[i], DbType.Int32, _random.Next(1, 10001)); + } + + var dataReader = dbCommand.ExecuteReader(CommandBehavior.Default & CommandBehavior.SequentialAccess); + + do + { + dataReader.Read(); + + worlds[j] = new World + { + Id = dataReader.GetInt32(0), + RandomNumber = dataReader.GetInt32(1) + }; + + j++; + } while (dataReader.NextResult()); + + dataReader.Close(); + + return worlds; + } + + public static string ReadColumn(IDataReader dataReader, int column) + { + long size = dataReader.GetBytes(column, 0, null, 0, 0); //get the length of data + byte[] values = new byte[size]; + + int bufferSize = 64; + long bytesRead = 0; + int currentPosition = 0; + + while (bytesRead < size) + { + bytesRead += dataReader.GetBytes(column, currentPosition, values, currentPosition, bufferSize); + currentPosition += bufferSize; + } + + return System.Text.Encoding.Default.GetString(values); + } + } +} \ No newline at end of file diff --git a/frameworks/CSharp/appmpower/src/appMpower.Orm/Serializers/IJsonSerializer.cs b/frameworks/CSharp/appmpower/src/appMpower.Orm/Serializers/IJsonSerializer.cs new file mode 100644 index 00000000000..8986ee387ee --- /dev/null +++ b/frameworks/CSharp/appmpower/src/appMpower.Orm/Serializers/IJsonSerializer.cs @@ -0,0 +1,9 @@ +using System.Text.Json; + +namespace appMpower.Orm.Serializers +{ + public interface IJsonSerializer + { + public void Serialize(Utf8JsonWriter utf8JsonWriter, T t); + } +} \ No newline at end of file diff --git a/frameworks/CSharp/appmpower/src/WorldSerializer.cs b/frameworks/CSharp/appmpower/src/appMpower.Orm/Serializers/WorldSerializer.cs similarity index 68% rename from frameworks/CSharp/appmpower/src/WorldSerializer.cs rename to frameworks/CSharp/appmpower/src/appMpower.Orm/Serializers/WorldSerializer.cs index 6150c5560b7..1e078da5957 100644 --- a/frameworks/CSharp/appmpower/src/WorldSerializer.cs +++ b/frameworks/CSharp/appmpower/src/appMpower.Orm/Serializers/WorldSerializer.cs @@ -1,8 +1,9 @@ using System.Text.Json; +using appMpower.Orm.Objects; -namespace appMpower +namespace appMpower.Orm.Serializers { - public class WorldSerializer : Kestrel.IJsonSerializer + public class WorldSerializer : IJsonSerializer { public void Serialize(Utf8JsonWriter utf8JsonWriter, World world) { @@ -10,6 +11,7 @@ public void Serialize(Utf8JsonWriter utf8JsonWriter, World world) utf8JsonWriter.WriteNumber("id", world.Id); utf8JsonWriter.WriteNumber("randomNumber", world.RandomNumber); utf8JsonWriter.WriteEndObject(); + utf8JsonWriter.Flush(); } } } diff --git a/frameworks/CSharp/appmpower/src/appMpower.Orm/Serializers/WorldsSerizalizer.cs b/frameworks/CSharp/appmpower/src/appMpower.Orm/Serializers/WorldsSerizalizer.cs new file mode 100644 index 00000000000..223af9bd702 --- /dev/null +++ b/frameworks/CSharp/appmpower/src/appMpower.Orm/Serializers/WorldsSerizalizer.cs @@ -0,0 +1,24 @@ +using System.Text.Json; +using appMpower.Orm.Objects; + +namespace appMpower.Orm.Serializers +{ + public class WorldsSerializer : IJsonSerializer + { + public void Serialize(Utf8JsonWriter utf8JsonWriter, World[] worlds) + { + utf8JsonWriter.WriteStartArray(); + + foreach (World world in worlds) + { + utf8JsonWriter.WriteStartObject(); + utf8JsonWriter.WriteNumber("id", world.Id); + utf8JsonWriter.WriteNumber("randomNumber", world.RandomNumber); + utf8JsonWriter.WriteEndObject(); + } + + utf8JsonWriter.WriteEndArray(); + utf8JsonWriter.Flush(); + } + } +} diff --git a/frameworks/CSharp/appmpower/src/appMpower.csproj b/frameworks/CSharp/appmpower/src/appMpower.Orm/appMpower.Orm.csproj similarity index 52% rename from frameworks/CSharp/appmpower/src/appMpower.csproj rename to frameworks/CSharp/appmpower/src/appMpower.Orm/appMpower.Orm.csproj index 579c54883b5..dd9c929f19f 100644 --- a/frameworks/CSharp/appmpower/src/appMpower.csproj +++ b/frameworks/CSharp/appmpower/src/appMpower.Orm/appMpower.Orm.csproj @@ -1,55 +1,42 @@ - - - - net8.0 - Exe - true - - - - - true - true - true - false - Speed - none - false - - - true - true - true - false - - - true - - true - - - - - true - - - true - false - false - - - - - - - - - - $(DefineConstants);POSTGRESQL - $(DefineConstants);ODBC - $(DefineConstants);ADO - - - \ No newline at end of file + + + + net8.0 + enable + + true + true + true + + linux-x64 + + + + + true + false + Size + none + false + + true + true + true + false + + true + + true + + true + + true + false + false + + + + + + + diff --git a/frameworks/CSharp/appmpower/src/appMpower/JsonMessage.cs b/frameworks/CSharp/appmpower/src/appMpower/JsonMessage.cs new file mode 100644 index 00000000000..ab1685ab8ad --- /dev/null +++ b/frameworks/CSharp/appmpower/src/appMpower/JsonMessage.cs @@ -0,0 +1,7 @@ +namespace appMpower +{ + public struct JsonMessage + { + public string Message { get; set; } + } +} \ No newline at end of file diff --git a/frameworks/CSharp/appmpower/src/appMpower/Middleware/CachingMiddelware.cs b/frameworks/CSharp/appmpower/src/appMpower/Middleware/CachingMiddelware.cs new file mode 100644 index 00000000000..0719f19c5ad --- /dev/null +++ b/frameworks/CSharp/appmpower/src/appMpower/Middleware/CachingMiddelware.cs @@ -0,0 +1,120 @@ +using System; +using System.Collections.Generic; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Primitives; + +namespace appMpower; + +public class CachingMiddleware +{ + private static readonly Dictionary _cache = new(); + private static readonly Random _random = new(); + + private static readonly byte[] _startBytes = Encoding.UTF8.GetBytes("["); + private static readonly byte[] _endBytes = Encoding.UTF8.GetBytes("]"); + private static readonly byte[] _comma = Encoding.UTF8.GetBytes(","); + + + private readonly static KeyValuePair _headerServer = + new KeyValuePair("Server", new StringValues("k")); + private readonly static KeyValuePair _headerContentType = + new KeyValuePair("Content-Type", new StringValues("application/json")); + + private readonly RequestDelegate _next; + + public CachingMiddleware(RequestDelegate next) + { + _next = next; + } + + public unsafe Task Invoke(HttpContext httpContext) + { + if (httpContext.Request.Path.StartsWithSegments("/cached-worlds", StringComparison.Ordinal)) + { + int payloadLength; + IntPtr handlePointer; + IntPtr bytePointer; + byte[] json; + + if (_cache.Count == 0) + { + for (int i = 1; i < 10001; i++) + { + bytePointer = NativeMethods.DbById(i, out payloadLength, out handlePointer); + json = new byte[payloadLength]; + Marshal.Copy(bytePointer, json, 0, payloadLength); + NativeMethods.FreeHandlePointer(handlePointer); + _cache.Add(i, json); + } + } + + var queryString = httpContext.Request.QueryString.ToString(); + int queries; + Int32.TryParse(queryString.Substring(queryString.LastIndexOf("=") + 1), out queries); + queries = queries > 500 ? 500 : (queries > 0 ? queries : 1); + + var response = httpContext.Response; + response.Headers.Add(_headerServer); + response.Headers.Add(_headerContentType); + + int queriesLength = 0; + int[] keys = new int[queries]; + + for (int i = 0; i < queries; i++) + { + keys[i] = _random.Next(1, 10001); + + if (!_cache.TryGetValue(keys[i], out json)) + { + bytePointer = NativeMethods.DbById(keys[i], out payloadLength, out handlePointer); + json = new byte[payloadLength]; + Marshal.Copy(bytePointer, json, 0, payloadLength); + NativeMethods.FreeHandlePointer(handlePointer); + _cache.Add(keys[i], json); + } + + queriesLength += json.Length; + } + + byte[] result = new byte[_startBytes.Length + _endBytes.Length + (_comma.Length * queries - 1) + queriesLength]; + int position = 0; + + Buffer.BlockCopy(_startBytes, 0, result, position, _startBytes.Length); + position += _startBytes.Length; + + for (int i = 0; i < queries; i++) + { + json = _cache[keys[i]]; + Buffer.BlockCopy(json, 0, result, position, json.Length); + position += json.Length; + + if (i < queries - 1) + { + Buffer.BlockCopy(_comma, 0, result, position, _comma.Length); + position += _comma.Length; + } + } + + Buffer.BlockCopy(_endBytes, 0, result, position, _endBytes.Length); + + response.Headers.Add( + new KeyValuePair("Content-Length", result.Length.ToString())); + + return response.Body.WriteAsync(result, 0, result.Length); + } + + return _next(httpContext); + } +} + +public static class CachingMiddlewareExtensions +{ + public static IApplicationBuilder UseCaching(this IApplicationBuilder builder) + { + return builder.UseMiddleware(); + } +} diff --git a/frameworks/CSharp/appmpower/src/appMpower/Middleware/FortunesMiddleware.cs b/frameworks/CSharp/appmpower/src/appMpower/Middleware/FortunesMiddleware.cs new file mode 100644 index 00000000000..2acf9af1716 --- /dev/null +++ b/frameworks/CSharp/appmpower/src/appMpower/Middleware/FortunesMiddleware.cs @@ -0,0 +1,58 @@ +using System; +using System.Collections.Generic; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Primitives; + +namespace appMpower; + +public class FortunesMiddleware +{ + private readonly static KeyValuePair _headerServer = + new KeyValuePair("Server", new StringValues("k")); + private readonly static KeyValuePair _headerContentType = + new KeyValuePair("Content-Type", new StringValues("text/html; charset=UTF-8")); + + private readonly RequestDelegate _next; + + public FortunesMiddleware(RequestDelegate next) + { + _next = next; + } + + public unsafe Task Invoke(HttpContext httpContext) + { + if (httpContext.Request.Path.StartsWithSegments("/fortunes", StringComparison.Ordinal)) + { + var response = httpContext.Response; + response.Headers.Add(_headerServer); + response.Headers.Add(_headerContentType); + + int payloadLength; + IntPtr handlePointer; + + IntPtr bytePointer = NativeMethods.Fortunes(out payloadLength, out handlePointer); + byte[] json = new byte[payloadLength]; + Marshal.Copy(bytePointer, json, 0, payloadLength); + NativeMethods.FreeHandlePointer(handlePointer); + + response.Headers.Add( + new KeyValuePair("Content-Length", payloadLength.ToString())); + + return response.Body.WriteAsync(json, 0, payloadLength); + } + + return _next(httpContext); + } +} + +public static class FortunesMiddlewareExtensions +{ + public static IApplicationBuilder UseFortunes(this IApplicationBuilder builder) + { + return builder.UseMiddleware(); + } +} diff --git a/frameworks/CSharp/appmpower/src/appMpower/Middleware/JsonMiddleware.cs b/frameworks/CSharp/appmpower/src/appMpower/Middleware/JsonMiddleware.cs new file mode 100644 index 00000000000..2e90051ff2f --- /dev/null +++ b/frameworks/CSharp/appmpower/src/appMpower/Middleware/JsonMiddleware.cs @@ -0,0 +1,64 @@ +using System; +using System.Collections.Generic; +using System.Text.Json; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Primitives; +using appMpower.Serializers; + +namespace appMpower; + +public class JsonMiddleware +{ + private readonly static JsonWriterOptions _jsonWriterOptions = new JsonWriterOptions + { + Indented = false, + SkipValidation = true + }; + + private readonly static JsonMessageSerializer _jsonMessageSerializer = new JsonMessageSerializer(); + + private readonly static KeyValuePair _headerServer = + new KeyValuePair("Server", new StringValues("k")); + private readonly static KeyValuePair _headerContentType = + new KeyValuePair("Content-Type", new StringValues("application/json")); + + private readonly RequestDelegate _nextStage; + + public JsonMiddleware(RequestDelegate nextStage) + { + _nextStage = nextStage; + } + + public unsafe Task Invoke(HttpContext httpContext) + { + if (httpContext.Request.Path.StartsWithSegments("/json", StringComparison.Ordinal)) + { + var response = httpContext.Response; + response.Headers.Add(_headerServer); + response.Headers.Add(_headerContentType); + + using var utf8JsonWriter = new Utf8JsonWriter(httpContext.Response.Body, _jsonWriterOptions); + + _jsonMessageSerializer.Serialize(utf8JsonWriter, new JsonMessage { Message = "Hello, World!" }); + + response.Headers.Add( + new KeyValuePair("Content-Length", utf8JsonWriter.BytesPending.ToString())); + + utf8JsonWriter.Flush(); + + return Task.CompletedTask; + } + + return _nextStage(httpContext); + } +} + +public static class JsonMiddlewareExtensions +{ + public static IApplicationBuilder UseJson(this IApplicationBuilder builder) + { + return builder.UseMiddleware(); + } +} \ No newline at end of file diff --git a/frameworks/CSharp/appmpower/src/appMpower/Middleware/MultipleQueriesMiddleware.cs b/frameworks/CSharp/appmpower/src/appMpower/Middleware/MultipleQueriesMiddleware.cs new file mode 100644 index 00000000000..63964f0b90c --- /dev/null +++ b/frameworks/CSharp/appmpower/src/appMpower/Middleware/MultipleQueriesMiddleware.cs @@ -0,0 +1,62 @@ +using System; +using System.Collections.Generic; +using System.Runtime.InteropServices; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Primitives; + +namespace appMpower; + +public class MultipleQueriesMiddleware +{ + private readonly static KeyValuePair _headerServer = + new KeyValuePair("Server", new StringValues("k")); + private readonly static KeyValuePair _headerContentType = + new KeyValuePair("Content-Type", new StringValues("application/json")); + + private readonly RequestDelegate _next; + + public MultipleQueriesMiddleware(RequestDelegate next) + { + _next = next; + } + + public unsafe Task Invoke(HttpContext httpContext) + { + if (httpContext.Request.Path.StartsWithSegments("/queries", StringComparison.Ordinal)) + { + var queryString = httpContext.Request.QueryString.ToString(); + int queries; + Int32.TryParse(queryString.Substring(queryString.LastIndexOf("=") + 1), out queries); + queries = queries > 500 ? 500 : (queries > 0 ? queries : 1); + + var response = httpContext.Response; + response.Headers.Add(_headerServer); + response.Headers.Add(_headerContentType); + + int payloadLength; + IntPtr handlePointer; + + IntPtr bytePointer = NativeMethods.Query(queries, out payloadLength, out handlePointer); + byte[] json = new byte[payloadLength]; + Marshal.Copy(bytePointer, json, 0, payloadLength); + NativeMethods.FreeHandlePointer(handlePointer); + + response.Headers.Add( + new KeyValuePair("Content-Length", payloadLength.ToString())); + + return response.Body.WriteAsync(json, 0, payloadLength); + } + + return _next(httpContext); + } +} + +public static class MultipleQueriesMiddlewareExtensions +{ + public static IApplicationBuilder UseMultipleQueries(this IApplicationBuilder builder) + { + return builder.UseMiddleware(); + } +} diff --git a/frameworks/CSharp/appmpower/src/appMpower/Middleware/MultipleUpdatesMiddleware.cs b/frameworks/CSharp/appmpower/src/appMpower/Middleware/MultipleUpdatesMiddleware.cs new file mode 100644 index 00000000000..5308afd3811 --- /dev/null +++ b/frameworks/CSharp/appmpower/src/appMpower/Middleware/MultipleUpdatesMiddleware.cs @@ -0,0 +1,62 @@ +using System; +using System.Collections.Generic; +using System.Runtime.InteropServices; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Primitives; + +namespace appMpower; + +public class MultipleUpdatesMiddelware +{ + private readonly static KeyValuePair _headerServer = + new KeyValuePair("Server", new StringValues("k")); + private readonly static KeyValuePair _headerContentType = + new KeyValuePair("Content-Type", new StringValues("application/json")); + + private readonly RequestDelegate _next; + + public MultipleUpdatesMiddelware(RequestDelegate next) + { + _next = next; + } + + public unsafe Task Invoke(HttpContext httpContext) + { + if (httpContext.Request.Path.StartsWithSegments("/updates", StringComparison.Ordinal)) + { + var queryString = httpContext.Request.QueryString.ToString(); + int count; + Int32.TryParse(queryString.Substring(queryString.LastIndexOf("=") + 1), out count); + count = count > 500 ? 500 : (count > 0 ? count : 1); + + var response = httpContext.Response; + response.Headers.Add(_headerServer); + response.Headers.Add(_headerContentType); + + int payloadLength; + IntPtr handlePointer; + + IntPtr bytePointer = NativeMethods.Updates(count, out payloadLength, out handlePointer); + byte[] json = new byte[payloadLength]; + Marshal.Copy(bytePointer, json, 0, payloadLength); + NativeMethods.FreeHandlePointer(handlePointer); + + response.Headers.Add( + new KeyValuePair("Content-Length", payloadLength.ToString())); + + return response.Body.WriteAsync(json, 0, payloadLength); + } + + return _next(httpContext); + } +} + +public static class MultipleUpdatesMiddelwareExtensions +{ + public static IApplicationBuilder UseMultipleUpdates(this IApplicationBuilder builder) + { + return builder.UseMiddleware(); + } +} diff --git a/frameworks/CSharp/appmpower/src/appMpower/Middleware/PlaintextMiddleware.cs b/frameworks/CSharp/appmpower/src/appMpower/Middleware/PlaintextMiddleware.cs new file mode 100644 index 00000000000..cf7ad20e54a --- /dev/null +++ b/frameworks/CSharp/appmpower/src/appMpower/Middleware/PlaintextMiddleware.cs @@ -0,0 +1,50 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Primitives; + +namespace appMpower; + +public unsafe class PlaintextMiddleware +{ + private readonly static KeyValuePair _headerServer = + new KeyValuePair("Server", new StringValues("k")); + private readonly static KeyValuePair _headerContentType = + new KeyValuePair("Content-Type", new StringValues("text/plain")); + private static readonly byte[] _helloWorldPayload = Encoding.UTF8.GetBytes("Hello, World!"); + + private readonly RequestDelegate _nextStage; + + public PlaintextMiddleware(RequestDelegate nextStage) + { + _nextStage = nextStage; + } + + public Task Invoke(HttpContext httpContext) + { + if (httpContext.Request.Path.StartsWithSegments("/plaintext", StringComparison.Ordinal)) + { + var payloadLength = _helloWorldPayload.Length; + var response = httpContext.Response; + response.Headers.Add(_headerServer); + response.Headers.Add(_headerContentType); + response.Headers.Add( + new KeyValuePair("Content-Length", payloadLength.ToString())); + + return response.Body.WriteAsync(_helloWorldPayload, 0, payloadLength); + } + + return _nextStage(httpContext); + } +} + +public static class PlaintextMiddlewareExtensions +{ + public static IApplicationBuilder UsePlainText(this IApplicationBuilder builder) + { + return builder.UseMiddleware(); + } +} diff --git a/frameworks/CSharp/appmpower/src/appMpower/Middleware/SingleQueryMiddleware.cs b/frameworks/CSharp/appmpower/src/appMpower/Middleware/SingleQueryMiddleware.cs new file mode 100644 index 00000000000..d43de484b66 --- /dev/null +++ b/frameworks/CSharp/appmpower/src/appMpower/Middleware/SingleQueryMiddleware.cs @@ -0,0 +1,57 @@ +using System; +using System.Collections.Generic; +using System.Runtime.InteropServices; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Primitives; + +namespace appMpower; + +public class SingleQueryMiddleware +{ + private readonly static KeyValuePair _headerServer = + new KeyValuePair("Server", new StringValues("k")); + private readonly static KeyValuePair _headerContentType = + new KeyValuePair("Content-Type", new StringValues("application/json")); + + private readonly RequestDelegate _nextStage; + + public SingleQueryMiddleware(RequestDelegate nextStage) + { + _nextStage = nextStage; + } + + public unsafe Task Invoke(HttpContext httpContext) + { + if (httpContext.Request.Path.StartsWithSegments("/db", StringComparison.Ordinal)) + { + var response = httpContext.Response; + response.Headers.Add(_headerServer); + response.Headers.Add(_headerContentType); + + int payloadLength; + IntPtr handlePointer; + + IntPtr bytePointer = NativeMethods.Db(out payloadLength, out handlePointer); + byte[] json = new byte[payloadLength]; + Marshal.Copy(bytePointer, json, 0, payloadLength); + NativeMethods.FreeHandlePointer(handlePointer); + + response.Headers.Add( + new KeyValuePair("Content-Length", payloadLength.ToString())); + + return response.Body.WriteAsync(json, 0, payloadLength); + } + + return _nextStage(httpContext); + } +} + +public static class SingleQueryMiddlewareExtensions +{ + public static IApplicationBuilder UseSingleQuery(this IApplicationBuilder builder) + { + return builder.UseMiddleware(); + } +} \ No newline at end of file diff --git a/frameworks/CSharp/appmpower/src/appMpower/NativeMethods.cs b/frameworks/CSharp/appmpower/src/appMpower/NativeMethods.cs new file mode 100644 index 00000000000..e24104d47fe --- /dev/null +++ b/frameworks/CSharp/appmpower/src/appMpower/NativeMethods.cs @@ -0,0 +1,62 @@ +using System; +using System.Runtime.InteropServices; + +public unsafe partial class NativeMethods +{ +#if DEBUG + [DllImport("appMpower.Orm.dylib", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)] +#else + [DllImport("appMpower.Orm.so", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)] +#endif + public static extern void Dbms(int dbms); + +#if DEBUG + [DllImport("appMpower.Orm.dylib", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)] +#else + [DllImport("appMpower.Orm.so", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)] +#endif + public static extern void DbProvider(int dbProvider); + +#if DEBUG + [DllImport("appMpower.Orm.dylib", CallingConvention = CallingConvention.Cdecl)] +#else + [DllImport("appMpower.Orm.so", CallingConvention = CallingConvention.Cdecl)] +#endif + public static extern void FreeHandlePointer(IntPtr handlePointer); + +#if DEBUG + [DllImport("appMpower.Orm.dylib", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)] +#else + [DllImport("appMpower.Orm.so", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)] +#endif + //public static extern byte* Db(out int length); + public static extern IntPtr Db(out int length, out IntPtr handlePointer); + +#if DEBUG + [DllImport("appMpower.Orm.dylib", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)] +#else + [DllImport("appMpower.Orm.so", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)] +#endif + public static extern IntPtr Fortunes(out int length, out IntPtr handlePointer); + +#if DEBUG + [DllImport("appMpower.Orm.dylib", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)] +#else + [DllImport("appMpower.Orm.so", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)] +#endif + public static extern IntPtr Query(int queries, out int length, out IntPtr handlePointer); + +#if DEBUG + [DllImport("appMpower.Orm.dylib", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)] +#else + [DllImport("appMpower.Orm.so", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)] +#endif + public static extern IntPtr Updates(int queries, out int length, out IntPtr handlePointer); + +#if DEBUG + [DllImport("appMpower.Orm.dylib", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)] +#else + [DllImport("appMpower.Orm.so", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)] +#endif + public static extern IntPtr DbById(int id, out int length, out IntPtr handlePointer); +} diff --git a/frameworks/CSharp/appmpower/src/appMpower/Program.cs b/frameworks/CSharp/appmpower/src/appMpower/Program.cs new file mode 100644 index 00000000000..f2f36aa627d --- /dev/null +++ b/frameworks/CSharp/appmpower/src/appMpower/Program.cs @@ -0,0 +1,44 @@ +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Hosting; + +namespace appMpower; + +class Program +{ + static void Main(string[] args) + { + BuildWebHost(args).Run(); + } + + static IHost BuildWebHost(string[] args) + { + var config = new ConfigurationBuilder() + .AddJsonFile("appsettings.json") + .AddEnvironmentVariables(prefix: "ASPNETCORE_") + .AddCommandLine(args) + .Build(); + + var appSettings = config.GetSection("AppSettings").Get(); + + var host = Host.CreateDefaultBuilder(args) + .ConfigureWebHostDefaults(webBuilder => + { + webBuilder.UseConfiguration(config) + .UseKestrel(options => + { + options.AddServerHeader = false; + options.AllowSynchronousIO = true; + }) + .UseStartup(); + }) + .Build(); + + return host; + } +} + +public class AppSettings +{ + public string Database { get; set; } +} diff --git a/frameworks/CSharp/appmpower/src/Kestrel/IJsonSerializer.cs b/frameworks/CSharp/appmpower/src/appMpower/Serializers/IJsonSerializer.cs similarity index 81% rename from frameworks/CSharp/appmpower/src/Kestrel/IJsonSerializer.cs rename to frameworks/CSharp/appmpower/src/appMpower/Serializers/IJsonSerializer.cs index 4f28a4cc538..eb59ff827ed 100644 --- a/frameworks/CSharp/appmpower/src/Kestrel/IJsonSerializer.cs +++ b/frameworks/CSharp/appmpower/src/appMpower/Serializers/IJsonSerializer.cs @@ -1,6 +1,6 @@ using System.Text.Json; -namespace appMpower.Kestrel +namespace appMpower.Serializers { public interface IJsonSerializer { diff --git a/frameworks/CSharp/appmpower/src/JsonMessageSerializer.cs b/frameworks/CSharp/appmpower/src/appMpower/Serializers/JsonMessageSerializer.cs similarity index 58% rename from frameworks/CSharp/appmpower/src/JsonMessageSerializer.cs rename to frameworks/CSharp/appmpower/src/appMpower/Serializers/JsonMessageSerializer.cs index dca7f673368..c06636f1a31 100644 --- a/frameworks/CSharp/appmpower/src/JsonMessageSerializer.cs +++ b/frameworks/CSharp/appmpower/src/appMpower/Serializers/JsonMessageSerializer.cs @@ -1,13 +1,13 @@ using System.Text.Json; -namespace appMpower +namespace appMpower.Serializers { - public class JsonMessageSerializer : Kestrel.IJsonSerializer + public class JsonMessageSerializer : IJsonSerializer { public void Serialize(Utf8JsonWriter utf8JsonWriter, JsonMessage jsonMessage) { utf8JsonWriter.WriteStartObject(); - utf8JsonWriter.WriteString("message", jsonMessage.message); + utf8JsonWriter.WriteString("message", jsonMessage.Message); utf8JsonWriter.WriteEndObject(); } } diff --git a/frameworks/CSharp/appmpower/src/appMpower/Startup.cs b/frameworks/CSharp/appmpower/src/appMpower/Startup.cs new file mode 100644 index 00000000000..4b571cf8286 --- /dev/null +++ b/frameworks/CSharp/appmpower/src/appMpower/Startup.cs @@ -0,0 +1,56 @@ +using System.Text.Encodings.Web; +using System.Text.Unicode; +using Microsoft.AspNetCore.Builder; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; + +namespace appMpower; + +public class Startup +{ + private readonly IConfiguration _configuration; + + public Startup(IConfiguration configuration) + { + _configuration = configuration; + } + + public void ConfigureServices(IServiceCollection services) + { + var appSettings = _configuration.Get(); + services.AddSingleton(appSettings); + +#if !DEBUG + #if ODBC + NativeMethods.DbProvider(1); //ODBC + #else + NativeMethods.DbProvider(0); //ADO + #endif + + #if POSTGRESQL + NativeMethods.Dbms(1); //PostgreSQL + #else + NativeMethods.Dbms(0); //MySQL + #endif +#endif + + var settings = new TextEncoderSettings(UnicodeRanges.BasicLatin, UnicodeRanges.Katakana, UnicodeRanges.Hiragana); + + settings.AllowCharacter('—'); + services.AddWebEncoders(options => + { + options.TextEncoderSettings = settings; + }); + } + + public void Configure(IApplicationBuilder app) + { + app.UsePlainText(); + app.UseJson(); + app.UseSingleQuery(); + app.UseCaching(); + app.UseFortunes(); + app.UseMultipleQueries(); + app.UseMultipleUpdates(); + } +} \ No newline at end of file diff --git a/frameworks/CSharp/appmpower/src/appMpower/appMpower.csproj b/frameworks/CSharp/appmpower/src/appMpower/appMpower.csproj new file mode 100644 index 00000000000..5661d01ce61 --- /dev/null +++ b/frameworks/CSharp/appmpower/src/appMpower/appMpower.csproj @@ -0,0 +1,35 @@ + + + + net8.0 + Exe + true + + + + + + + + + + + + + + + + $(DefineConstants);ODBC + $(DefineConstants);POSTGRESQL + $(DefineConstants);MYSQL + + + \ No newline at end of file diff --git a/frameworks/CSharp/appmpower/src/appMpower/appsettings.json b/frameworks/CSharp/appmpower/src/appMpower/appsettings.json new file mode 100644 index 00000000000..0b1badf0626 --- /dev/null +++ b/frameworks/CSharp/appmpower/src/appMpower/appsettings.json @@ -0,0 +1,9 @@ +{ + "Logging": { + "LogLevel": { + "Default": "None", + "Microsoft": "None", + "Microsoft.Hosting.Lifetime": "None" + } + } +} diff --git a/frameworks/CSharp/appmpower/src/nuget.config b/frameworks/CSharp/appmpower/src/appMpower/nuget.config similarity index 100% rename from frameworks/CSharp/appmpower/src/nuget.config rename to frameworks/CSharp/appmpower/src/appMpower/nuget.config diff --git a/frameworks/CSharp/appmpower/src/src.sln b/frameworks/CSharp/appmpower/src/src.sln new file mode 100644 index 00000000000..bedda48f506 --- /dev/null +++ b/frameworks/CSharp/appmpower/src/src.sln @@ -0,0 +1,28 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.0.31903.59 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "appMpower.Orm", "appMpower.Orm\appMpower.Orm.csproj", "{1EC05247-7299-4F69-887B-3B746DF5F878}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "appMpower", "appMpower\appMpower.csproj", "{EB5D3496-53B9-49A7-A3AD-754078142F81}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {1EC05247-7299-4F69-887B-3B746DF5F878}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1EC05247-7299-4F69-887B-3B746DF5F878}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1EC05247-7299-4F69-887B-3B746DF5F878}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1EC05247-7299-4F69-887B-3B746DF5F878}.Release|Any CPU.Build.0 = Release|Any CPU + {EB5D3496-53B9-49A7-A3AD-754078142F81}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {EB5D3496-53B9-49A7-A3AD-754078142F81}.Debug|Any CPU.Build.0 = Debug|Any CPU + {EB5D3496-53B9-49A7-A3AD-754078142F81}.Release|Any CPU.ActiveCfg = Release|Any CPU + {EB5D3496-53B9-49A7-A3AD-754078142F81}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection +EndGlobal From 2fa6c6512603b8852703c30a51b2c90e57eeef84 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 22 Aug 2024 20:50:23 +0000 Subject: [PATCH 081/204] Bump rexml from 3.3.3 to 3.3.6 in /frameworks/Ruby/rack Bumps [rexml](https://github.com/ruby/rexml) from 3.3.3 to 3.3.6. - [Release notes](https://github.com/ruby/rexml/releases) - [Changelog](https://github.com/ruby/rexml/blob/master/NEWS.md) - [Commits](https://github.com/ruby/rexml/compare/v3.3.3...v3.3.6) --- updated-dependencies: - dependency-name: rexml dependency-type: indirect ... Signed-off-by: dependabot[bot] --- frameworks/Ruby/rack/Gemfile.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frameworks/Ruby/rack/Gemfile.lock b/frameworks/Ruby/rack/Gemfile.lock index 7a08fdf7195..f3224c850b1 100644 --- a/frameworks/Ruby/rack/Gemfile.lock +++ b/frameworks/Ruby/rack/Gemfile.lock @@ -86,7 +86,7 @@ GEM rainbow (3.1.1) raindrops (0.20.1) regexp_parser (2.9.2) - rexml (3.3.3) + rexml (3.3.6) strscan rubocop (1.64.1) json (~> 2.3) From 19580460e86ab14aba9f40f65aeede53ff8b159b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 23 Aug 2024 19:07:31 +0000 Subject: [PATCH 082/204] Bump diesel from 1.4.6 to 2.2.3 in /frameworks/Rust/tide Bumps [diesel](https://github.com/diesel-rs/diesel) from 1.4.6 to 2.2.3. - [Release notes](https://github.com/diesel-rs/diesel/releases) - [Changelog](https://github.com/diesel-rs/diesel/blob/v2.2.3/CHANGELOG.md) - [Commits](https://github.com/diesel-rs/diesel/compare/v1.4.6...v2.2.3) --- updated-dependencies: - dependency-name: diesel dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- frameworks/Rust/tide/Cargo.lock | 178 ++++++++++++++++++++++++++------ frameworks/Rust/tide/Cargo.toml | 2 +- 2 files changed, 150 insertions(+), 30 deletions(-) diff --git a/frameworks/Rust/tide/Cargo.lock b/frameworks/Rust/tide/Cargo.lock index e9aa1d8598d..7ed70839854 100644 --- a/frameworks/Rust/tide/Cargo.lock +++ b/frameworks/Rust/tide/Cargo.lock @@ -93,7 +93,7 @@ checksum = "ca2925c4c290382f9d2fa3d1c1b6a63fa1427099721ecca4749b154cc9c25522" dependencies = [ "askama_shared", "proc-macro2", - "syn", + "syn 1.0.60", ] [[package]] @@ -116,7 +116,7 @@ dependencies = [ "proc-macro2", "quote", "serde", - "syn", + "syn 1.0.60", "toml", ] @@ -127,7 +127,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a3203e79f4dd9bdda415ed03cf14dae5a2bf775c683a00f94e9cd1faf0f596e5" dependencies = [ "quote", - "syn", + "syn 1.0.60", ] [[package]] @@ -331,7 +331,7 @@ checksum = "8d3a45e77e34375a7923b1e8febb049bb011f064714a8e17a1a616fef01da13d" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.60", ] [[package]] @@ -380,6 +380,12 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" +[[package]] +name = "bitflags" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" + [[package]] name = "bitvec" version = "0.19.4" @@ -609,7 +615,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e8f45d9ad417bcef4817d614a501ab55cdd96a6fdb24f49aab89a54acfd66b19" dependencies = [ "quote", - "syn", + "syn 1.0.60", ] [[package]] @@ -621,6 +627,41 @@ dependencies = [ "cipher", ] +[[package]] +name = "darling" +version = "0.20.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f63b86c8a8826a49b8c21f08a2d07338eec8d900540f8630dc76284be802989" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.20.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95133861a8032aaea082871032f5815eb9e98cef03fa916ab4500513994df9e5" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn 2.0.75", +] + +[[package]] +name = "darling_macro" +version = "0.20.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" +dependencies = [ + "darling_core", + "quote", + "syn 2.0.75", +] + [[package]] name = "dashmap" version = "4.0.2" @@ -639,26 +680,38 @@ checksum = "3ee2393c4a91429dffb4bedf19f4d6abf27d8a732c8ce4980305d782e5426d57" [[package]] name = "diesel" -version = "1.4.6" +version = "2.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "047bfc4d5c3bd2ef6ca6f981941046113524b9a9f9a7cbdfdd7ff40f58e6f542" +checksum = "65e13bab2796f412722112327f3e575601a3e9cdcbe426f0d30dbf43f3f5dc71" dependencies = [ - "bitflags", + "bitflags 2.6.0", "byteorder", "diesel_derives", + "itoa 1.0.11", "pq-sys", "r2d2", ] [[package]] name = "diesel_derives" -version = "1.4.1" +version = "2.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45f5098f628d02a7a0f68ddba586fb61e80edec3bdc1be3b921f4ceec60858d3" +checksum = "e7f2c3de51e2ba6bf2a648285696137aaf0f5f487bcbea93972fe8a364e131a4" dependencies = [ + "diesel_table_macro_syntax", + "dsl_auto_type", "proc-macro2", "quote", - "syn", + "syn 2.0.75", +] + +[[package]] +name = "diesel_table_macro_syntax" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "209c735641a413bc68c4923a9d6ad4bcb3ca306b794edaa7eb0b3228a99ffb25" +dependencies = [ + "syn 2.0.75", ] [[package]] @@ -676,6 +729,26 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "212d0f5754cb6769937f4501cc0e67f4f4483c8d2c3e1e922ee9edbe4ab4c7c0" +[[package]] +name = "dsl_auto_type" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5d9abe6314103864cc2d8901b7ae224e0ab1a103a0a416661b4097b0779b607" +dependencies = [ + "darling", + "either", + "heck", + "proc-macro2", + "quote", + "syn 2.0.75", +] + +[[package]] +name = "either" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" + [[package]] name = "event-listener" version = "2.5.1" @@ -707,6 +780,12 @@ dependencies = [ "web-sys", ] +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + [[package]] name = "form_urlencoded" version = "1.0.1" @@ -768,7 +847,7 @@ dependencies = [ "proc-macro-hack", "proc-macro2", "quote", - "syn", + "syn 1.0.60", ] [[package]] @@ -837,6 +916,12 @@ dependencies = [ "web-sys", ] +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + [[package]] name = "hermit-abi" version = "0.1.18" @@ -923,6 +1008,12 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6cab2627acfc432780848602f3f558f7e9dd427352224b0d9324025796d2a5e" +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + [[package]] name = "idna" version = "0.2.2" @@ -955,6 +1046,12 @@ version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736" +[[package]] +name = "itoa" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" + [[package]] name = "js-sys" version = "0.3.48" @@ -986,7 +1083,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "21f866863575d0e1d654fbeeabdc927292fdf862873dc3c96c6f753357e13374" dependencies = [ "arrayvec", - "bitflags", + "bitflags 1.2.1", "cfg-if 1.0.0", "ryu", "static_assertions", @@ -1153,7 +1250,7 @@ checksum = "758669ae3558c6f74bd2a18b41f7ac0b5a195aea6639d6a9b5e5d1ad5ba24c0b" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.60", ] [[package]] @@ -1227,18 +1324,18 @@ checksum = "bc881b2c22681370c6a780e47af9840ef841837bc98118431d4e1868bd0c1086" [[package]] name = "proc-macro2" -version = "1.0.24" +version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71" +checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" dependencies = [ - "unicode-xid", + "unicode-ident", ] [[package]] name = "quote" -version = "1.0.9" +version = "1.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7" +checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" dependencies = [ "proc-macro2", ] @@ -1317,7 +1414,7 @@ version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94341e4e44e24f6b591b59e47a8a027df12e008d73fd5672dbea9cc22f4507d9" dependencies = [ - "bitflags", + "bitflags 1.2.1", ] [[package]] @@ -1388,7 +1485,7 @@ checksum = "9391c295d64fc0abb2c556bad848f33cb8296276b1ad2677d1ae1ace4f258f31" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.60", ] [[package]] @@ -1397,7 +1494,7 @@ version = "1.0.63" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "43535db9747a4ba938c0ce0a98cc631a46ebf943c9e1d604e091df6007620bf6" dependencies = [ - "itoa", + "itoa 0.4.7", "ryu", "serde", ] @@ -1421,7 +1518,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "edfa57a7f8d9c1d260a549e7224100f6c43d43f9103e06dd8b4095a9b2b43ce9" dependencies = [ "form_urlencoded", - "itoa", + "itoa 0.4.7", "ryu", "serde", ] @@ -1541,7 +1638,7 @@ dependencies = [ "quote", "serde", "serde_derive", - "syn", + "syn 1.0.60", ] [[package]] @@ -1557,7 +1654,7 @@ dependencies = [ "serde_derive", "serde_json", "sha1", - "syn", + "syn 1.0.60", ] [[package]] @@ -1566,6 +1663,12 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "213701ba3370744dcd1a12960caa4843b3d68b4d1c0a5d575e0d65b2ee9d16c0" +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + [[package]] name = "subtle" version = "2.4.0" @@ -1589,6 +1692,17 @@ dependencies = [ "unicode-xid", ] +[[package]] +name = "syn" +version = "2.0.75" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6af063034fc1935ede7be0122941bafa9bacb949334d090b77ca98b5817c7d9" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + [[package]] name = "tap" version = "1.0.1" @@ -1612,7 +1726,7 @@ checksum = "7765189610d8241a44529806d6fd1f2e0a08734313a35d5b3a556f92b381f3c0" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.60", ] [[package]] @@ -1697,7 +1811,7 @@ dependencies = [ "proc-macro2", "quote", "standback", - "syn", + "syn 1.0.60", ] [[package]] @@ -1739,6 +1853,12 @@ dependencies = [ "matches", ] +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + [[package]] name = "unicode-normalization" version = "0.1.17" @@ -1840,7 +1960,7 @@ dependencies = [ "log", "proc-macro2", "quote", - "syn", + "syn 1.0.60", "wasm-bindgen-shared", ] @@ -1874,7 +1994,7 @@ checksum = "cc053ec74d454df287b9374ee8abb36ffd5acb95ba87da3ba5b7d3fe20eb401e" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.60", "wasm-bindgen-backend", "wasm-bindgen-shared", ] diff --git a/frameworks/Rust/tide/Cargo.toml b/frameworks/Rust/tide/Cargo.toml index 80c05675a77..18b2aeea38c 100644 --- a/frameworks/Rust/tide/Cargo.toml +++ b/frameworks/Rust/tide/Cargo.toml @@ -8,7 +8,7 @@ edition = "2018" askama = "0.10.5" async-std = { version = "1.9.0", features = ["attributes"] } async-trait = "0.1.42" -diesel = { version = "1.4.6", features = ["postgres", "r2d2"] } +diesel = { version = "2.2.3", features = ["postgres", "r2d2"] } http-types = "2.10.0" rand = { version = "0.7", features = ["small_rng"] } serde = { version = "1.0.123", features = ["derive"] } From 0ffacd956b5354a9c5848e61e0d2ea85af262c14 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9A=D0=BE=D1=81=D1=82=D1=8F=20=D0=A2=D1=80=D0=B5=D1=82?= =?UTF-8?q?=D1=8F=D0=BA?= Date: Mon, 26 Aug 2024 19:12:32 +0300 Subject: [PATCH 083/204] refactor(ditsmod): upgrade Ditsmod, removed bun specific TypeScript code (#9216) * chore(ditsmod): upgrade Ditsmod, removed bun.lockb and bun-providers.ts. * refactor(ditsmod): removed bun specific TypeScript code. * refactor(ditsmod): significantly simplifying the structure of the app and reducing the number of tests. --- frameworks/TypeScript/ditsmod/.gitignore | 1 + .../TypeScript/ditsmod/benchmark_config.json | 149 ++---------------- frameworks/TypeScript/ditsmod/bun.lockb | Bin 59387 -> 0 bytes .../ditsmod/ditsmod-bun-mysql.dockerfile | 3 +- .../ditsmod/ditsmod-bun-postgres.dockerfile | 3 +- .../TypeScript/ditsmod/ditsmod-bun.dockerfile | 3 +- frameworks/TypeScript/ditsmod/package.json | 7 +- .../TypeScript/ditsmod/src/app/app.module.ts | 19 ++- .../app/bun-integration/bun-application.ts | 17 -- .../src/app/bun-integration/bun-providers.ts | 21 --- .../src/app/bun-integration/node-res.ts | 61 ------- .../src/app/bun-integration/pre-router.ts | 26 --- .../ditsmod/src/app/bun-integration/spawn.ts | 9 -- .../{modules/service/db => }/db.service.ts | 2 +- .../ditsmod/src/app/{utils => }/helper.ts | 2 +- .../service/db => }/init.extension.ts | 0 .../modules/routed/simple/db.controller.ts | 39 ----- .../modules/routed/simple/db.controller2.ts | 40 ----- .../routed/simple/fortune.controller.ts | 41 ----- .../routed/simple/fortune.controller2.ts | 43 ----- .../modules/routed/simple/simple.module.ts | 23 --- .../routed/simple/singleton.controller.ts | 18 --- .../routed/simple/without-db.controller.ts | 18 --- .../src/app/modules/service/db/db.module.ts | 13 -- .../{modules/service/db => }/mysql.service.ts | 0 .../ditsmod/src/app/one.controller.ts | 88 +++++++++++ .../service/db => }/postgres.service.ts | 0 .../app/{modules/service/db => }/tokens.ts | 0 .../src/app/{modules/service/db => }/types.ts | 0 frameworks/TypeScript/ditsmod/src/main.bun.ts | 12 -- frameworks/TypeScript/ditsmod/tsconfig.json | 6 - 31 files changed, 116 insertions(+), 548 deletions(-) delete mode 100755 frameworks/TypeScript/ditsmod/bun.lockb delete mode 100644 frameworks/TypeScript/ditsmod/src/app/bun-integration/bun-application.ts delete mode 100644 frameworks/TypeScript/ditsmod/src/app/bun-integration/bun-providers.ts delete mode 100644 frameworks/TypeScript/ditsmod/src/app/bun-integration/node-res.ts delete mode 100644 frameworks/TypeScript/ditsmod/src/app/bun-integration/pre-router.ts delete mode 100644 frameworks/TypeScript/ditsmod/src/app/bun-integration/spawn.ts rename frameworks/TypeScript/ditsmod/src/app/{modules/service/db => }/db.service.ts (96%) rename frameworks/TypeScript/ditsmod/src/app/{utils => }/helper.ts (90%) rename frameworks/TypeScript/ditsmod/src/app/{modules/service/db => }/init.extension.ts (100%) delete mode 100644 frameworks/TypeScript/ditsmod/src/app/modules/routed/simple/db.controller.ts delete mode 100644 frameworks/TypeScript/ditsmod/src/app/modules/routed/simple/db.controller2.ts delete mode 100644 frameworks/TypeScript/ditsmod/src/app/modules/routed/simple/fortune.controller.ts delete mode 100644 frameworks/TypeScript/ditsmod/src/app/modules/routed/simple/fortune.controller2.ts delete mode 100644 frameworks/TypeScript/ditsmod/src/app/modules/routed/simple/simple.module.ts delete mode 100644 frameworks/TypeScript/ditsmod/src/app/modules/routed/simple/singleton.controller.ts delete mode 100644 frameworks/TypeScript/ditsmod/src/app/modules/routed/simple/without-db.controller.ts delete mode 100644 frameworks/TypeScript/ditsmod/src/app/modules/service/db/db.module.ts rename frameworks/TypeScript/ditsmod/src/app/{modules/service/db => }/mysql.service.ts (100%) create mode 100644 frameworks/TypeScript/ditsmod/src/app/one.controller.ts rename frameworks/TypeScript/ditsmod/src/app/{modules/service/db => }/postgres.service.ts (100%) rename frameworks/TypeScript/ditsmod/src/app/{modules/service/db => }/tokens.ts (100%) rename frameworks/TypeScript/ditsmod/src/app/{modules/service/db => }/types.ts (100%) delete mode 100644 frameworks/TypeScript/ditsmod/src/main.bun.ts diff --git a/frameworks/TypeScript/ditsmod/.gitignore b/frameworks/TypeScript/ditsmod/.gitignore index b7c122d83c3..d525fa34c07 100644 --- a/frameworks/TypeScript/ditsmod/.gitignore +++ b/frameworks/TypeScript/ditsmod/.gitignore @@ -5,3 +5,4 @@ dist* .pnp* nodemon.json package-lock.json +bun.lockb diff --git a/frameworks/TypeScript/ditsmod/benchmark_config.json b/frameworks/TypeScript/ditsmod/benchmark_config.json index c16c9419bde..11704b96a53 100755 --- a/frameworks/TypeScript/ditsmod/benchmark_config.json +++ b/frameworks/TypeScript/ditsmod/benchmark_config.json @@ -3,6 +3,7 @@ "tests": [ { "default": { + "dockerfile": "ditsmod.dockerfile", "json_url": "/json", "plaintext_url": "/plaintext", "port": 8080, @@ -17,31 +18,12 @@ "webserver": "None", "os": "Linux", "database_os": "Linux", - "display_name": "Ditsmod", - "notes": "", - "versus": "nodejs" - }, - "simplified-di": { - "dockerfile": "ditsmod.dockerfile", - "json_url": "/json2", - "plaintext_url": "/plaintext2", - "port": 8080, - "approach": "Realistic", - "classification": "Micro", - "database": "None", - "framework": "Ditsmod", - "language": "TypeScript", - "flavor": "None", - "orm": "None", - "platform": "nodejs", - "webserver": "None", - "os": "Linux", - "database_os": "Linux", - "display_name": "ditsmod [simplified use of di]", + "display_name": "ditsmod", "notes": "Simplified use of Dependency Injection (no request level injector).", "versus": "nodejs" }, "postgres": { + "dockerfile": "ditsmod-postgres.dockerfile", "db_url": "/db", "query_url": "/queries?queries=", "update_url": "/updates?queries=", @@ -60,10 +42,11 @@ "os": "Linux", "database_os": "Linux", "display_name": "ditsmod [postgres]", - "notes": "", + "notes": "Simplified use of Dependency Injection (no request level injector).", "versus": "nodejs" }, "mysql": { + "dockerfile": "ditsmod-mysql.dockerfile", "db_url": "/db", "query_url": "/queries?queries=", "update_url": "/updates?queries=", @@ -82,52 +65,6 @@ "os": "Linux", "database_os": "Linux", "display_name": "ditsmod [mysql]", - "notes": "", - "versus": "nodejs" - }, - "postgres2": { - "dockerfile": "ditsmod-postgres.dockerfile", - "db_url": "/db2", - "query_url": "/queries2?queries=", - "update_url": "/updates2?queries=", - "cached_query_url": "/cached-queries2?count=", - "fortune_url": "/fortunes2", - "port": 8080, - "approach": "Realistic", - "classification": "Micro", - "database": "Postgres", - "framework": "Ditsmod", - "language": "TypeScript", - "flavor": "None", - "orm": "Raw", - "platform": "nodejs", - "webserver": "None", - "os": "Linux", - "database_os": "Linux", - "display_name": "ditsmod [postgres & simplified use of di]", - "notes": "Simplified use of Dependency Injection (no request level injector).", - "versus": "nodejs" - }, - "mysql2": { - "dockerfile": "ditsmod-mysql.dockerfile", - "db_url": "/db2", - "query_url": "/queries2?queries=", - "update_url": "/updates2?queries=", - "cached_query_url": "/cached-queries2?count=", - "fortune_url": "/fortunes2", - "port": 8080, - "approach": "Realistic", - "classification": "Micro", - "database": "MySQL", - "framework": "Ditsmod", - "language": "TypeScript", - "flavor": "None", - "orm": "Raw", - "platform": "nodejs", - "webserver": "None", - "os": "Linux", - "database_os": "Linux", - "display_name": "ditsmod [mysql & simplified use of di]", "notes": "Simplified use of Dependency Injection (no request level injector).", "versus": "nodejs" }, @@ -139,7 +76,7 @@ "approach": "Realistic", "classification": "Micro", "database": "None", - "framework": "Ditsmod", + "framework": "ditsmod-bun", "language": "TypeScript", "flavor": "None", "orm": "None", @@ -147,27 +84,7 @@ "webserver": "None", "os": "Linux", "database_os": "Linux", - "display_name": "Ditsmod on bun", - "notes": "", - "versus": "bun" - }, - "simplified-di-bun": { - "dockerfile": "ditsmod-bun.dockerfile", - "json_url": "/json2", - "plaintext_url": "/plaintext2", - "port": 8080, - "approach": "Realistic", - "classification": "Micro", - "database": "None", - "framework": "Ditsmod", - "language": "TypeScript", - "flavor": "None", - "orm": "None", - "platform": "bun", - "webserver": "None", - "os": "Linux", - "database_os": "Linux", - "display_name": "ditsmod on bun [simplified use of di]", + "display_name": "ditsmod on bun", "notes": "Simplified use of Dependency Injection (no request level injector).", "versus": "bun" }, @@ -182,7 +99,7 @@ "approach": "Realistic", "classification": "Micro", "database": "Postgres", - "framework": "Ditsmod", + "framework": "ditsmod-bun", "language": "TypeScript", "flavor": "None", "orm": "Raw", @@ -191,7 +108,7 @@ "os": "Linux", "database_os": "Linux", "display_name": "ditsmod on bun [postgres]", - "notes": "", + "notes": "Simplified use of Dependency Injection (no request level injector).", "versus": "bun" }, "mysql-bun": { @@ -205,7 +122,7 @@ "approach": "Realistic", "classification": "Micro", "database": "MySQL", - "framework": "Ditsmod", + "framework": "ditsmod-bun", "language": "TypeScript", "flavor": "None", "orm": "Raw", @@ -214,52 +131,6 @@ "os": "Linux", "database_os": "Linux", "display_name": "ditsmod on bun [mysql]", - "notes": "", - "versus": "bun" - }, - "postgres2-bun": { - "dockerfile": "ditsmod-bun-postgres.dockerfile", - "db_url": "/db2", - "query_url": "/queries2?queries=", - "update_url": "/updates2?queries=", - "cached_query_url": "/cached-queries2?count=", - "fortune_url": "/fortunes2", - "port": 8080, - "approach": "Realistic", - "classification": "Micro", - "database": "Postgres", - "framework": "Ditsmod", - "language": "TypeScript", - "flavor": "None", - "orm": "Raw", - "platform": "bun", - "webserver": "None", - "os": "Linux", - "database_os": "Linux", - "display_name": "ditsmod on bun [postgres & simplified use of di]", - "notes": "Simplified use of Dependency Injection (no request level injector).", - "versus": "bun" - }, - "mysql2-bun": { - "dockerfile": "ditsmod-bun-mysql.dockerfile", - "db_url": "/db2", - "query_url": "/queries2?queries=", - "update_url": "/updates2?queries=", - "cached_query_url": "/cached-queries2?count=", - "fortune_url": "/fortunes2", - "port": 8080, - "approach": "Realistic", - "classification": "Micro", - "database": "MySQL", - "framework": "Ditsmod", - "language": "TypeScript", - "flavor": "None", - "orm": "Raw", - "platform": "bun", - "webserver": "None", - "os": "Linux", - "database_os": "Linux", - "display_name": "ditsmod on bun [mysql & simplified use of di]", "notes": "Simplified use of Dependency Injection (no request level injector).", "versus": "bun" } diff --git a/frameworks/TypeScript/ditsmod/bun.lockb b/frameworks/TypeScript/ditsmod/bun.lockb deleted file mode 100755 index c15ebbf0d57fa7a70302adedf5ceb815a5c211fa..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 59387 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 diff --git a/frameworks/TypeScript/ditsmod/ditsmod-bun-mysql.dockerfile b/frameworks/TypeScript/ditsmod/ditsmod-bun-mysql.dockerfile index c6c56b41443..d0f44000dc7 100644 --- a/frameworks/TypeScript/ditsmod/ditsmod-bun-mysql.dockerfile +++ b/frameworks/TypeScript/ditsmod/ditsmod-bun-mysql.dockerfile @@ -6,7 +6,6 @@ RUN bun install RUN bun run build ENV NODE_ENV production -ENV IS_BUN true ENV DATABASE mysql ENV MYSQL_HOST tfb-database ENV MYSQL_USER benchmarkdbuser @@ -14,4 +13,4 @@ ENV MYSQL_PSWD benchmarkdbpass ENV MYSQL_DBNAME hello_world EXPOSE 8080 -CMD rm node_modules/@ditsmod/*/tsconfig.json && bun src/app/bun-integration/spawn.ts +CMD rm node_modules/@ditsmod/*/tsconfig.json && bun dist/main.js diff --git a/frameworks/TypeScript/ditsmod/ditsmod-bun-postgres.dockerfile b/frameworks/TypeScript/ditsmod/ditsmod-bun-postgres.dockerfile index 6d10f0bfc7b..1bcc29a8b2f 100644 --- a/frameworks/TypeScript/ditsmod/ditsmod-bun-postgres.dockerfile +++ b/frameworks/TypeScript/ditsmod/ditsmod-bun-postgres.dockerfile @@ -6,7 +6,6 @@ RUN bun install RUN bun run build ENV NODE_ENV production -ENV IS_BUN true ENV DATABASE postgres ENV PG_HOST tfb-database ENV PG_USER benchmarkdbuser @@ -14,4 +13,4 @@ ENV PG_PSWD benchmarkdbpass ENV PG_DBNAME hello_world EXPOSE 8080 -CMD rm node_modules/@ditsmod/*/tsconfig.json && bun src/app/bun-integration/spawn.ts +CMD rm node_modules/@ditsmod/*/tsconfig.json && bun dist/main.js diff --git a/frameworks/TypeScript/ditsmod/ditsmod-bun.dockerfile b/frameworks/TypeScript/ditsmod/ditsmod-bun.dockerfile index d18c49cab44..8f0268556af 100644 --- a/frameworks/TypeScript/ditsmod/ditsmod-bun.dockerfile +++ b/frameworks/TypeScript/ditsmod/ditsmod-bun.dockerfile @@ -6,7 +6,6 @@ RUN bun install RUN bun run build ENV NODE_ENV production -ENV IS_BUN true EXPOSE 8080 -CMD rm node_modules/@ditsmod/*/tsconfig.json && bun src/app/bun-integration/spawn.ts +CMD rm node_modules/@ditsmod/*/tsconfig.json && bun dist/main.js diff --git a/frameworks/TypeScript/ditsmod/package.json b/frameworks/TypeScript/ditsmod/package.json index 3d74a7822de..a4d1ec09851 100755 --- a/frameworks/TypeScript/ditsmod/package.json +++ b/frameworks/TypeScript/ditsmod/package.json @@ -10,16 +10,11 @@ "build": "tsc -b tsconfig.build.json", "clean": "rm -rf dist*" }, - "imports": { - "#routed/*": "./dist/app/modules/routed/*", - "#service/*": "./dist/app/modules/service/*", - "#utils/*": "./dist/app/utils/*" - }, "keywords": [], "author": "Костя Третяк", "license": "MIT", "dependencies": { - "@ditsmod/core": "~2.54.2", + "@ditsmod/core": "~2.55.0", "@ditsmod/routing": "~2.3.0", "handlebars": "^4.7.8", "lru-cache": "^11.0.0", diff --git a/frameworks/TypeScript/ditsmod/src/app/app.module.ts b/frameworks/TypeScript/ditsmod/src/app/app.module.ts index e0c1dfedcec..34bfc4357cf 100644 --- a/frameworks/TypeScript/ditsmod/src/app/app.module.ts +++ b/frameworks/TypeScript/ditsmod/src/app/app.module.ts @@ -1,13 +1,16 @@ -import { PreRouter, rootModule } from '@ditsmod/core'; +import { Providers, rootModule } from '@ditsmod/core'; +import { PRE_ROUTER_EXTENSIONS, RoutingModule } from '@ditsmod/routing'; -import { SimpleModule } from '#routed/simple/simple.module.js'; -import { BunPreRouter } from './bun-integration/pre-router.js'; -import { BunProviders } from './bun-integration/bun-providers.js'; +import { OneController } from './one.controller.js'; +import { DbService } from './db.service.js'; +import { InitExtension } from './init.extension.js'; +import { DB_INIT_EXTENSIONS } from './tokens.js'; +import { ModelService } from './types.js'; @rootModule({ - appends: [SimpleModule], - providersPerApp: [ - ...new BunProviders().useLogConfig({ level: 'off' }).if(process.env.IS_BUN).useClass(PreRouter, BunPreRouter), - ], + imports: [RoutingModule], + providersPerApp: new Providers().passThrough(DbService).passThrough(ModelService).useLogConfig({ level: 'off' }), + extensions: [{ extension: InitExtension, groupToken: DB_INIT_EXTENSIONS, nextToken: PRE_ROUTER_EXTENSIONS }], + controllers: [OneController], }) export class AppModule {} diff --git a/frameworks/TypeScript/ditsmod/src/app/bun-integration/bun-application.ts b/frameworks/TypeScript/ditsmod/src/app/bun-integration/bun-application.ts deleted file mode 100644 index 0b462db87bb..00000000000 --- a/frameworks/TypeScript/ditsmod/src/app/bun-integration/bun-application.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { AnyFn, AppInitializer, Application } from '@ditsmod/core'; -import { Serve, Server } from 'bun'; - -export class BunApplication extends Application { - protected override createServer(requestListener: any): any { - const serveOptions = this.appOptions.serverOptions as Serve; - serveOptions.fetch ??= (req) => requestListener(req); - return Bun.serve(serveOptions); - } - - protected override async createServerAndBindToListening(appInitializer: AppInitializer, resolve: AnyFn) { - this.flushLogs(); - const server = (await this.createServer(appInitializer.requestListener)) as Server; - this.systemLogMediator.serverListen(this, server.hostname, server.port); - resolve({ server }); - } -} diff --git a/frameworks/TypeScript/ditsmod/src/app/bun-integration/bun-providers.ts b/frameworks/TypeScript/ditsmod/src/app/bun-integration/bun-providers.ts deleted file mode 100644 index 0581973f421..00000000000 --- a/frameworks/TypeScript/ditsmod/src/app/bun-integration/bun-providers.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { Providers, Class } from '@ditsmod/core'; - -export class BunProviders extends Providers { - protected setCondition?: boolean; - protected ifCondition?: boolean; - - if(condition: any) { - this.setCondition = true; - this.ifCondition = condition; - return this; - } - - override useClass(token: A, useClass: B, multi?: boolean): this { - if (!this.setCondition || this.ifCondition) { - this.pushProvider({ token, useClass }, multi); - } - this.setCondition = undefined; - this.ifCondition = undefined; - return this; - } -} diff --git a/frameworks/TypeScript/ditsmod/src/app/bun-integration/node-res.ts b/frameworks/TypeScript/ditsmod/src/app/bun-integration/node-res.ts deleted file mode 100644 index 7dae8de27a6..00000000000 --- a/frameworks/TypeScript/ditsmod/src/app/bun-integration/node-res.ts +++ /dev/null @@ -1,61 +0,0 @@ -import { Writable } from 'node:stream'; - -export class NodeRes extends Writable { - #chunks: Buffer[] = []; - #resolve: (body: string) => void; - status: number = 200; - headers = {} as HeadersInit; - body = new Promise((resolve) => (this.#resolve = resolve)); - headersSent?: boolean; - statusText?: string; - - set statusCode(statusCode: number) { - this.status = statusCode; - } - - getHeader(name: string) { - return this.headers[name as keyof HeadersInit]; - } - - getHeaders() { - return this.headers; - } - - setHeader(name: string, value: number | string | readonly string[]) { - this.headers = { ...this.headers, [name]: value } as HeadersInit; - return this; - } - - writeHead(statusCode: number, headers?: HeadersInit): this; - writeHead(statusCode: number, statusMessage: string, headers?: HeadersInit): this; - writeHead(statusCode: number, statusMsgOrHeaders?: string | HeadersInit, headers?: HeadersInit): this { - this.status = statusCode; - if (typeof statusMsgOrHeaders == 'object') { - this.mergeHeaders(statusMsgOrHeaders); - } else { - this.statusText = statusMsgOrHeaders; - this.mergeHeaders(headers); - } - return this; - } - - override _write(chunk: any, encoding: BufferEncoding, callback: (error?: Error | null) => void): void { - this.#chunks.push(Buffer.from(chunk)); - callback(); - } - - override _final(callback: (error?: Error | null) => void): void { - const finalData = Buffer.concat(this.#chunks); - this.headersSent = true; - this.#resolve(finalData.toString()); - callback(); - } - - protected mergeHeaders(headers: HeadersInit = {}) { - if (Array.isArray(headers)) { - headers.forEach(([key, val]) => ((this.headers as any)[key] = val)); - } else { - this.headers = { ...this.headers, ...headers }; - } - } -} diff --git a/frameworks/TypeScript/ditsmod/src/app/bun-integration/pre-router.ts b/frameworks/TypeScript/ditsmod/src/app/bun-integration/pre-router.ts deleted file mode 100644 index 26a0100e4e0..00000000000 --- a/frameworks/TypeScript/ditsmod/src/app/bun-integration/pre-router.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { PreRouter } from '@ditsmod/core'; -import { NodeRes } from './node-res.js'; - -export class BunPreRouter extends PreRouter { - override requestListener: any = async (req: Request) => { - const nodeReq = req as any; - const nodeRes = new NodeRes(); - - const url = new URL(req.url); - const uri = url.pathname; - const queryString = url.search.slice(1); - const { handle, params } = this.router.find(req.method as any, uri); - if (!handle) { - this.sendNotImplemented(nodeRes as any); - const body = await nodeRes.body; - return new Response(body, nodeRes); - } - - await handle(nodeReq, nodeRes as any, params!, queryString).catch((err) => { - this.sendInternalServerError(nodeRes as any, err); - }); - - const body = await nodeRes.body; - return new Response(body, nodeRes); - }; -} diff --git a/frameworks/TypeScript/ditsmod/src/app/bun-integration/spawn.ts b/frameworks/TypeScript/ditsmod/src/app/bun-integration/spawn.ts deleted file mode 100644 index 439451029a4..00000000000 --- a/frameworks/TypeScript/ditsmod/src/app/bun-integration/spawn.ts +++ /dev/null @@ -1,9 +0,0 @@ -import os from 'node:os'; - -const numCPUs = os.cpus().length; -for (let i = 0; i < numCPUs; i++) { - Bun.spawn(['bun', 'dist/main.bun.js'], { - stdio: ['inherit', 'inherit', 'inherit'], - env: { ...process.env }, - }); -} diff --git a/frameworks/TypeScript/ditsmod/src/app/modules/service/db/db.service.ts b/frameworks/TypeScript/ditsmod/src/app/db.service.ts similarity index 96% rename from frameworks/TypeScript/ditsmod/src/app/modules/service/db/db.service.ts rename to frameworks/TypeScript/ditsmod/src/app/db.service.ts index 61c9b5bbfbd..1267c11f360 100644 --- a/frameworks/TypeScript/ditsmod/src/app/modules/service/db/db.service.ts +++ b/frameworks/TypeScript/ditsmod/src/app/db.service.ts @@ -1,8 +1,8 @@ import { injectable } from '@ditsmod/core'; import { LRUCache } from 'lru-cache'; -import { getNumberOfObjects, getRandomNumber } from '#utils/helper.js'; import { ModelService, World } from './types.js'; +import { getNumberOfObjects, getRandomNumber } from './helper.js'; @injectable() export class DbService { diff --git a/frameworks/TypeScript/ditsmod/src/app/utils/helper.ts b/frameworks/TypeScript/ditsmod/src/app/helper.ts similarity index 90% rename from frameworks/TypeScript/ditsmod/src/app/utils/helper.ts rename to frameworks/TypeScript/ditsmod/src/app/helper.ts index 33a0cb20ad6..3adcffe4fef 100644 --- a/frameworks/TypeScript/ditsmod/src/app/utils/helper.ts +++ b/frameworks/TypeScript/ditsmod/src/app/helper.ts @@ -1,4 +1,4 @@ -import { Fortune } from '#service/db/types.js'; +import { Fortune } from './types.js'; export function getRandomNumber() { return Math.floor(Math.random() * 10000) + 1; diff --git a/frameworks/TypeScript/ditsmod/src/app/modules/service/db/init.extension.ts b/frameworks/TypeScript/ditsmod/src/app/init.extension.ts similarity index 100% rename from frameworks/TypeScript/ditsmod/src/app/modules/service/db/init.extension.ts rename to frameworks/TypeScript/ditsmod/src/app/init.extension.ts diff --git a/frameworks/TypeScript/ditsmod/src/app/modules/routed/simple/db.controller.ts b/frameworks/TypeScript/ditsmod/src/app/modules/routed/simple/db.controller.ts deleted file mode 100644 index ac39c4bc715..00000000000 --- a/frameworks/TypeScript/ditsmod/src/app/modules/routed/simple/db.controller.ts +++ /dev/null @@ -1,39 +0,0 @@ -import { AnyObj, controller, inject, QUERY_PARAMS, Res, route } from '@ditsmod/core'; - -import { DbService } from '#service/db/db.service.js'; -import { getRandomNumber } from '#utils/helper.js'; - -@controller() -export class DbController { - constructor( - private res: Res, - private dbService: DbService, - ) { - res.nodeRes.setHeader('Server', 'Ditsmod'); - } - - @route('GET', 'db') - async getSingleQuery() { - const id = getRandomNumber(); - const result = await this.dbService.findOneWorld(id); - this.res.sendJson(result); - } - - @route('GET', 'queries') - async getMultiQueries(@inject(QUERY_PARAMS) queryParams: AnyObj) { - const result = await this.dbService.getMultiQueries(queryParams.queries); - this.res.sendJson(result); - } - - @route('GET', 'cached-queries') - async getCachedWorlds(@inject(QUERY_PARAMS) queryParams: AnyObj) { - const result = await this.dbService.getMultiQueries(queryParams.count, false); - this.res.sendJson(result); - } - - @route('GET', 'updates') - async getUpdates(@inject(QUERY_PARAMS) queryParams: AnyObj) { - const worlds = await this.dbService.saveWorlds(queryParams.queries); - this.res.sendJson(worlds); - } -} diff --git a/frameworks/TypeScript/ditsmod/src/app/modules/routed/simple/db.controller2.ts b/frameworks/TypeScript/ditsmod/src/app/modules/routed/simple/db.controller2.ts deleted file mode 100644 index cef38bd4d0b..00000000000 --- a/frameworks/TypeScript/ditsmod/src/app/modules/routed/simple/db.controller2.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { AnyObj, controller, RequestContext, SingletonRequestContext, route } from '@ditsmod/core'; - -import { DbService } from '#service/db/db.service.js'; -import { getRandomNumber } from '#utils/helper.js'; - -@controller({ isSingleton: true }) -export class DbController2 { - constructor(private dbService: DbService) {} - - @route('GET', 'db2') - async getSingleQuery(ctx: RequestContext) { - const id = getRandomNumber(); - const result = await this.dbService.findOneWorld(id); - this.sendJson(ctx, result); - } - - @route('GET', 'queries2') - async getMultiQueries(ctx: SingletonRequestContext) { - const result = await this.dbService.getMultiQueries(ctx.queryParams!.queries); - this.sendJson(ctx, result); - } - - @route('GET', 'cached-queries2') - async getCachedWorlds(ctx: SingletonRequestContext) { - const result = await this.dbService.getMultiQueries(ctx.queryParams!.count, false); - this.sendJson(ctx, result); - } - - @route('GET', 'updates2') - async getUpdates(ctx: SingletonRequestContext) { - const worlds = await this.dbService.saveWorlds(ctx.queryParams!.queries); - this.sendJson(ctx, worlds); - } - - protected sendJson(ctx: RequestContext, value: AnyObj) { - ctx.nodeRes.setHeader('Server', 'Ditsmod'); - ctx.nodeRes.setHeader('Content-Type', 'application/json; charset=utf-8'); - ctx.nodeRes.end(JSON.stringify(value)); - } -} diff --git a/frameworks/TypeScript/ditsmod/src/app/modules/routed/simple/fortune.controller.ts b/frameworks/TypeScript/ditsmod/src/app/modules/routed/simple/fortune.controller.ts deleted file mode 100644 index 64c6b087cc5..00000000000 --- a/frameworks/TypeScript/ditsmod/src/app/modules/routed/simple/fortune.controller.ts +++ /dev/null @@ -1,41 +0,0 @@ -import Handlebars from 'handlebars'; -import { NODE_RES, NodeResponse, controller, inject, route } from '@ditsmod/core'; - -import { additionalFortune, compare } from '#utils/helper.js'; -import { DbService } from '#service/db/db.service.js'; - -const tmpl = Handlebars.compile( - [ - '', - '', - 'Fortunes', - '', - '', - '', - '', - '', - '', - '{{#fortunes}}', - '', - '', - '', - '', - '{{/fortunes}}', - '
idmessage
{{id}}{{message}}
', - '', - '', - ].join(''), -); - -@controller() -export class FortuneController { - @route('GET', 'fortunes') - async fortunes(@inject(NODE_RES) nodeRes: NodeResponse, dbService: DbService) { - const fortunes = await dbService.findAllFortunes(); - fortunes.push(additionalFortune); - fortunes.sort(compare); - nodeRes.setHeader('Server', 'Ditsmod'); - nodeRes.setHeader('Content-Type', 'text/html; charset=utf-8'); - nodeRes.end(tmpl({ fortunes })); - } -} diff --git a/frameworks/TypeScript/ditsmod/src/app/modules/routed/simple/fortune.controller2.ts b/frameworks/TypeScript/ditsmod/src/app/modules/routed/simple/fortune.controller2.ts deleted file mode 100644 index 5100a0dcb54..00000000000 --- a/frameworks/TypeScript/ditsmod/src/app/modules/routed/simple/fortune.controller2.ts +++ /dev/null @@ -1,43 +0,0 @@ -import Handlebars from 'handlebars'; -import { RequestContext, controller, route } from '@ditsmod/core'; - -import { additionalFortune, compare } from '#utils/helper.js'; -import { DbService } from '#service/db/db.service.js'; - -const tmpl = Handlebars.compile( - [ - '', - '', - 'Fortunes', - '', - '', - '', - '', - '', - '', - '{{#fortunes}}', - '', - '', - '', - '', - '{{/fortunes}}', - '
idmessage
{{id}}{{message}}
', - '', - '', - ].join(''), -); - -@controller({ isSingleton: true }) -export class FortuneController2 { - constructor(private dbService: DbService) {} - - @route('GET', 'fortunes2') - async fortunes(ctx: RequestContext) { - const fortunes = await this.dbService.findAllFortunes(); - fortunes.push(additionalFortune); - fortunes.sort(compare); - ctx.nodeRes.setHeader('Server', 'Ditsmod'); - ctx.nodeRes.setHeader('Content-Type', 'text/html; charset=utf-8'); - ctx.nodeRes.end(tmpl({ fortunes })); - } -} diff --git a/frameworks/TypeScript/ditsmod/src/app/modules/routed/simple/simple.module.ts b/frameworks/TypeScript/ditsmod/src/app/modules/routed/simple/simple.module.ts deleted file mode 100644 index 123681d91aa..00000000000 --- a/frameworks/TypeScript/ditsmod/src/app/modules/routed/simple/simple.module.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { featureModule } from '@ditsmod/core'; -import { RoutingModule } from '@ditsmod/routing'; - -import { DbModule } from '#service/db/db.module.js'; -import { WithoutDbController } from './without-db.controller.js'; -import { DbController } from './db.controller.js'; -import { FortuneController } from './fortune.controller.js'; -import { SingletonController } from './singleton.controller.js'; -import { DbController2 } from './db.controller2.js'; -import { FortuneController2 } from './fortune.controller2.js'; - -@featureModule({ - imports: [RoutingModule, DbModule], - controllers: [ - WithoutDbController, - DbController, - DbController2, - FortuneController, - FortuneController2, - SingletonController, - ], -}) -export class SimpleModule {} diff --git a/frameworks/TypeScript/ditsmod/src/app/modules/routed/simple/singleton.controller.ts b/frameworks/TypeScript/ditsmod/src/app/modules/routed/simple/singleton.controller.ts deleted file mode 100644 index 3661775e536..00000000000 --- a/frameworks/TypeScript/ditsmod/src/app/modules/routed/simple/singleton.controller.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { controller, route, SingletonRequestContext } from '@ditsmod/core'; - -@controller({ isSingleton: true }) -export class SingletonController { - @route('GET', 'plaintext2') - getHello(ctx: SingletonRequestContext) { - ctx.nodeRes.setHeader('Server', 'Ditsmod'); - ctx.nodeRes.setHeader('Content-Type', 'text/plain; charset=utf-8'); - ctx.nodeRes.end('Hello, World!'); - } - - @route('GET', 'json2') - getJson(ctx: SingletonRequestContext) { - ctx.nodeRes.setHeader('Server', 'Ditsmod'); - ctx.nodeRes.setHeader('Content-Type', 'application/json; charset=utf-8'); - ctx.nodeRes.end(JSON.stringify({ message: 'Hello, World!' })); - } -} diff --git a/frameworks/TypeScript/ditsmod/src/app/modules/routed/simple/without-db.controller.ts b/frameworks/TypeScript/ditsmod/src/app/modules/routed/simple/without-db.controller.ts deleted file mode 100644 index 9ff5246609f..00000000000 --- a/frameworks/TypeScript/ditsmod/src/app/modules/routed/simple/without-db.controller.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { controller, Res, route } from '@ditsmod/core'; - -@controller() -export class WithoutDbController { - constructor(private res: Res) { - res.nodeRes.setHeader('Server', 'Ditsmod'); - } - - @route('GET', 'plaintext') - getHello() { - this.res.send('Hello, World!'); - } - - @route('GET', 'json') - getJson() { - this.res.sendJson({ message: 'Hello, World!' }); - } -} diff --git a/frameworks/TypeScript/ditsmod/src/app/modules/service/db/db.module.ts b/frameworks/TypeScript/ditsmod/src/app/modules/service/db/db.module.ts deleted file mode 100644 index 08de21fb22a..00000000000 --- a/frameworks/TypeScript/ditsmod/src/app/modules/service/db/db.module.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { featureModule } from '@ditsmod/core'; -import { PRE_ROUTER_EXTENSIONS } from '@ditsmod/routing'; - -import { DbService } from './db.service.js'; -import { InitExtension } from './init.extension.js'; -import { DB_INIT_EXTENSIONS } from './tokens.js'; -import { ModelService } from './types.js'; - -@featureModule({ - providersPerApp: [DbService, ModelService], - extensions: [{ extension: InitExtension, groupToken: DB_INIT_EXTENSIONS, nextToken: PRE_ROUTER_EXTENSIONS }], -}) -export class DbModule {} diff --git a/frameworks/TypeScript/ditsmod/src/app/modules/service/db/mysql.service.ts b/frameworks/TypeScript/ditsmod/src/app/mysql.service.ts similarity index 100% rename from frameworks/TypeScript/ditsmod/src/app/modules/service/db/mysql.service.ts rename to frameworks/TypeScript/ditsmod/src/app/mysql.service.ts diff --git a/frameworks/TypeScript/ditsmod/src/app/one.controller.ts b/frameworks/TypeScript/ditsmod/src/app/one.controller.ts new file mode 100644 index 00000000000..09615c93598 --- /dev/null +++ b/frameworks/TypeScript/ditsmod/src/app/one.controller.ts @@ -0,0 +1,88 @@ +import { AnyObj, controller, RequestContext, SingletonRequestContext, route } from '@ditsmod/core'; +import Handlebars from 'handlebars'; + +import { DbService } from './db.service.js'; +import { additionalFortune, compare, getRandomNumber } from './helper.js'; + +const tmpl = Handlebars.compile( + [ + '', + '', + 'Fortunes', + '', + '', + '', + '', + '', + '', + '{{#fortunes}}', + '', + '', + '', + '', + '{{/fortunes}}', + '
idmessage
{{id}}{{message}}
', + '', + '', + ].join(''), +); + +@controller({ isSingleton: true }) +export class OneController { + constructor(private dbService: DbService) {} + + @route('GET', 'db') + async getSingleQuery(ctx: RequestContext) { + const id = getRandomNumber(); + const result = await this.dbService.findOneWorld(id); + this.sendJson(ctx, result); + } + + @route('GET', 'queries') + async getMultiQueries(ctx: SingletonRequestContext) { + const result = await this.dbService.getMultiQueries(ctx.queryParams!.queries); + this.sendJson(ctx, result); + } + + @route('GET', 'cached-queries') + async getCachedWorlds(ctx: SingletonRequestContext) { + const result = await this.dbService.getMultiQueries(ctx.queryParams!.count, false); + this.sendJson(ctx, result); + } + + @route('GET', 'updates') + async getUpdates(ctx: SingletonRequestContext) { + const worlds = await this.dbService.saveWorlds(ctx.queryParams!.queries); + this.sendJson(ctx, worlds); + } + + @route('GET', 'fortunes') + async fortunes(ctx: RequestContext) { + const fortunes = await this.dbService.findAllFortunes(); + fortunes.push(additionalFortune); + fortunes.sort(compare); + ctx.nodeRes.setHeader('Server', 'Ditsmod'); + ctx.nodeRes.setHeader('Content-Type', 'text/html; charset=utf-8'); + ctx.nodeRes.end(tmpl({ fortunes })); + } + + @route('GET', 'plaintext') + getHello(ctx: SingletonRequestContext) { + ctx.nodeRes.setHeader('Server', 'Ditsmod'); + ctx.nodeRes.setHeader('Content-Type', 'text/plain; charset=utf-8'); + ctx.nodeRes.end('Hello, World!'); + } + + @route('GET', 'json') + getJson(ctx: SingletonRequestContext) { + ctx.nodeRes.setHeader('Server', 'Ditsmod'); + ctx.nodeRes.setHeader('Content-Type', 'application/json; charset=utf-8'); + ctx.nodeRes.end(JSON.stringify({ message: 'Hello, World!' })); + } + + protected sendJson(ctx: RequestContext, value: AnyObj) { + ctx.nodeRes.setHeader('Server', 'Ditsmod'); + ctx.nodeRes.setHeader('Content-Type', 'application/json; charset=utf-8'); + ctx.nodeRes.end(JSON.stringify(value)); + } +} diff --git a/frameworks/TypeScript/ditsmod/src/app/modules/service/db/postgres.service.ts b/frameworks/TypeScript/ditsmod/src/app/postgres.service.ts similarity index 100% rename from frameworks/TypeScript/ditsmod/src/app/modules/service/db/postgres.service.ts rename to frameworks/TypeScript/ditsmod/src/app/postgres.service.ts diff --git a/frameworks/TypeScript/ditsmod/src/app/modules/service/db/tokens.ts b/frameworks/TypeScript/ditsmod/src/app/tokens.ts similarity index 100% rename from frameworks/TypeScript/ditsmod/src/app/modules/service/db/tokens.ts rename to frameworks/TypeScript/ditsmod/src/app/tokens.ts diff --git a/frameworks/TypeScript/ditsmod/src/app/modules/service/db/types.ts b/frameworks/TypeScript/ditsmod/src/app/types.ts similarity index 100% rename from frameworks/TypeScript/ditsmod/src/app/modules/service/db/types.ts rename to frameworks/TypeScript/ditsmod/src/app/types.ts diff --git a/frameworks/TypeScript/ditsmod/src/main.bun.ts b/frameworks/TypeScript/ditsmod/src/main.bun.ts deleted file mode 100644 index 42c0798a066..00000000000 --- a/frameworks/TypeScript/ditsmod/src/main.bun.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { Serve, Server } from 'bun'; - -import { AppModule } from './app/app.module.js'; -import { BunApplication } from './app/bun-integration/bun-application.js'; - -const reusePort = process.env.NODE_ENV == 'production'; -const serverOptions = { port: 8080, hostname: '0.0.0.0', reusePort } as Serve; -const { server } = await new BunApplication().bootstrap(AppModule, { - serverOptions: serverOptions as any, -}); - -const bunServer = server as unknown as Server; diff --git a/frameworks/TypeScript/ditsmod/tsconfig.json b/frameworks/TypeScript/ditsmod/tsconfig.json index ef1b58e6cb3..34983f83409 100644 --- a/frameworks/TypeScript/ditsmod/tsconfig.json +++ b/frameworks/TypeScript/ditsmod/tsconfig.json @@ -17,12 +17,6 @@ "strictPropertyInitialization": false, "allowJs": false, "types": ["bun-types"], - // Bun works with bugs if this code is uncommented. - // "paths": { - // "#routed/*": ["./src/app/modules/routed/*"], - // "#service/*": ["./src/app/modules/service/*"], - // "#utils/*": ["./src/app/utils/*"], - // } }, "include": [ "src", From 404f8899abaa38b6b745b3435b54533991df9eea Mon Sep 17 00:00:00 2001 From: Sanskar Jethi <29942790+sansyrox@users.noreply.github.com> Date: Mon, 26 Aug 2024 17:28:20 +0100 Subject: [PATCH 084/204] chore: update robyn to latest version (#9217) * chore: update robyn to latest version * update v number --- frameworks/Python/robyn/app-const.py | 18 +++++++----------- frameworks/Python/robyn/app.py | 17 +++++++---------- frameworks/Python/robyn/benchmark_config.json | 3 ++- frameworks/Python/robyn/requirements-const.txt | 2 +- frameworks/Python/robyn/requirements.txt | 2 +- frameworks/Python/robyn/robyn-const.dockerfile | 2 +- frameworks/Python/robyn/robyn.dockerfile | 2 +- 7 files changed, 20 insertions(+), 26 deletions(-) diff --git a/frameworks/Python/robyn/app-const.py b/frameworks/Python/robyn/app-const.py index e082ff1b129..4b806389fa5 100755 --- a/frameworks/Python/robyn/app-const.py +++ b/frameworks/Python/robyn/app-const.py @@ -1,15 +1,15 @@ import multiprocessing import os -from robyn import Response, Robyn, jsonify +from robyn import Response, Robyn from robyn.argument_parser import Config class SpecialConfig(Config): def __init__(self): super().__init__() - self.workers = 2 - self.processes = (os.cpu_count() * 2) + 1 + self.workers = (os.cpu_count() * 2) + 1 + self.processes = os.cpu_count() self.log_level = "WARN" @@ -22,16 +22,12 @@ def plaintext() -> str: @app.get("/json", const=True) -def json() -> str: - return Response( - status_code=200, - description=jsonify({"message": "Hello, world!"}), - headers={"Content-Type": "application/json"} - ) - +def json() -> dict: + return { + "message": "Hello, world!" + } if __name__ == "__main__": app.add_response_header("Server", "Robyn") - app.start(host="0.0.0.0", port=8080) diff --git a/frameworks/Python/robyn/app.py b/frameworks/Python/robyn/app.py index 798b67026e2..e8c975e530f 100755 --- a/frameworks/Python/robyn/app.py +++ b/frameworks/Python/robyn/app.py @@ -1,15 +1,15 @@ import multiprocessing import os -from robyn import Response, Robyn, jsonify +from robyn import Response, Robyn from robyn.argument_parser import Config class SpecialConfig(Config): def __init__(self): super().__init__() - self.workers = 2 - self.processes = (os.cpu_count() * 2) + 1 + self.workers = (os.cpu_count() * 2) + 1 + self.processes = os.cpu_count() self.log_level = "WARN" @@ -22,13 +22,10 @@ def plaintext() -> str: @app.get("/json") -def json() -> str: - return Response( - status_code=200, - description=jsonify({"message": "Hello, world!"}), - headers={"Content-Type": "application/json"} - ) - +def json() -> dict: + return { + "message": "Hello, world!" + } if __name__ == "__main__": app.add_response_header("Server", "Roby1n") diff --git a/frameworks/Python/robyn/benchmark_config.json b/frameworks/Python/robyn/benchmark_config.json index 3d8c6baa8a3..46cd72fe4c6 100755 --- a/frameworks/Python/robyn/benchmark_config.json +++ b/frameworks/Python/robyn/benchmark_config.json @@ -38,4 +38,5 @@ } } ] -} \ No newline at end of file +} + diff --git a/frameworks/Python/robyn/requirements-const.txt b/frameworks/Python/robyn/requirements-const.txt index 0056c1d2876..fbb88344955 100644 --- a/frameworks/Python/robyn/requirements-const.txt +++ b/frameworks/Python/robyn/requirements-const.txt @@ -1,2 +1,2 @@ uvloop==0.19.0 -robyn==0.45.0 +robyn==0.60.2 diff --git a/frameworks/Python/robyn/requirements.txt b/frameworks/Python/robyn/requirements.txt index 0056c1d2876..fbb88344955 100644 --- a/frameworks/Python/robyn/requirements.txt +++ b/frameworks/Python/robyn/requirements.txt @@ -1,2 +1,2 @@ uvloop==0.19.0 -robyn==0.45.0 +robyn==0.60.2 diff --git a/frameworks/Python/robyn/robyn-const.dockerfile b/frameworks/Python/robyn/robyn-const.dockerfile index a12c64e248f..90b201eccff 100644 --- a/frameworks/Python/robyn/robyn-const.dockerfile +++ b/frameworks/Python/robyn/robyn-const.dockerfile @@ -8,4 +8,4 @@ RUN pip3 install -r /robyn/requirements-const.txt EXPOSE 8080 -CMD ["python", "app-const.py", "--log-level", "warn"]] +CMD ["robyn", "app-const.py", "--fast"] diff --git a/frameworks/Python/robyn/robyn.dockerfile b/frameworks/Python/robyn/robyn.dockerfile index bc42b5be462..8de6fea2c19 100644 --- a/frameworks/Python/robyn/robyn.dockerfile +++ b/frameworks/Python/robyn/robyn.dockerfile @@ -8,4 +8,4 @@ RUN pip3 install -r /robyn/requirements.txt EXPOSE 8080 -CMD ["python", "app.py", "--log-level", "warn"] +CMD ["robyn", "app.py", "--fast"] From 3db2b8d977018b4af298255739b12ca20311513a Mon Sep 17 00:00:00 2001 From: itrofimow Date: Mon, 26 Aug 2024 20:28:36 +0400 Subject: [PATCH 085/204] [C++] [userver] bump userver commit, improve application scalability (#9219) * bump userver commit * improve scalability * fix the configs --- frameworks/C++/userver/userver-bare.dockerfile | 2 +- frameworks/C++/userver/userver.dockerfile | 2 +- frameworks/C++/userver/userver_configs/static_config.yaml | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/frameworks/C++/userver/userver-bare.dockerfile b/frameworks/C++/userver/userver-bare.dockerfile index a318a9601b7..92f8cdaa080 100644 --- a/frameworks/C++/userver/userver-bare.dockerfile +++ b/frameworks/C++/userver/userver-bare.dockerfile @@ -6,7 +6,7 @@ RUN apt update && \ WORKDIR /src RUN git clone https://github.com/userver-framework/userver.git && \ - cd userver && git checkout ec1a3b07793f8d4cd0968cd61d8e6079d667a1e7 + cd userver && git checkout bdd5e1e03921ff378b062f86a189c3cfa3d66332 COPY userver_benchmark/ ./ RUN mkdir build && cd build && \ diff --git a/frameworks/C++/userver/userver.dockerfile b/frameworks/C++/userver/userver.dockerfile index 9b45edd2418..5f4755e3714 100644 --- a/frameworks/C++/userver/userver.dockerfile +++ b/frameworks/C++/userver/userver.dockerfile @@ -6,7 +6,7 @@ RUN apt update && \ WORKDIR /src RUN git clone https://github.com/userver-framework/userver.git && \ - cd userver && git checkout ec1a3b07793f8d4cd0968cd61d8e6079d667a1e7 + cd userver && git checkout bdd5e1e03921ff378b062f86a189c3cfa3d66332 COPY userver_benchmark/ ./ RUN mkdir build && cd build && \ diff --git a/frameworks/C++/userver/userver_configs/static_config.yaml b/frameworks/C++/userver/userver_configs/static_config.yaml index 2bdcf1fbce5..4d7a7878912 100644 --- a/frameworks/C++/userver/userver_configs/static_config.yaml +++ b/frameworks/C++/userver/userver_configs/static_config.yaml @@ -1,8 +1,7 @@ # yaml components_manager: event_thread_pool: - threads: 9 - dedicated_timer_threads: 1 + threads: 8 coro_pool: initial_size: 10000 # Preallocate 10000 coroutines at startup. max_size: 300000 # Do not keep more than 300000 preallocated coroutines. @@ -12,8 +11,9 @@ components_manager: main-task-processor: # Make a task processor for CPU-bound couroutine tasks. thread_name: main-worker # OS will show the threads of this task processor with 'main-worker' prefix. - worker_threads: 46 + worker_threads: 48 guess-cpu-limit: true + task-processor-queue: work-stealing-task-queue fs-task-processor: # Make a separate task processor for filesystem bound tasks. thread_name: fs-worker From 9e58d22fdf5d4a3a77c6df727d4c02d670274e19 Mon Sep 17 00:00:00 2001 From: Nikolay Kim Date: Mon, 26 Aug 2024 21:28:57 +0500 Subject: [PATCH 086/204] [ntex] replace async-std with compio runtime (#9222) * ntex: replace async-std with compio * wip * wip --- frameworks/Rust/ntex/Cargo.toml | 21 ++++++++++++------- frameworks/Rust/ntex/benchmark_config.json | 12 +++++------ frameworks/Rust/ntex/config.toml | 6 +++--- ...astd.dockerfile => ntex-compio.dockerfile} | 4 ++-- ...d.dockerfile => ntex-db-compio.dockerfile} | 4 ++-- ....dockerfile => ntex-plt-compio.dockerfile} | 4 ++-- frameworks/Rust/ntex/src/main.rs | 1 - frameworks/Rust/ntex/src/main_plt.rs | 2 +- 8 files changed, 30 insertions(+), 24 deletions(-) rename frameworks/Rust/ntex/{ntex-astd.dockerfile => ntex-compio.dockerfile} (84%) rename frameworks/Rust/ntex/{ntex-db-astd.dockerfile => ntex-db-compio.dockerfile} (84%) rename frameworks/Rust/ntex/{ntex-plt-astd.dockerfile => ntex-plt-compio.dockerfile} (83%) diff --git a/frameworks/Rust/ntex/Cargo.toml b/frameworks/Rust/ntex/Cargo.toml index 92c0da890ac..850e640f2ad 100755 --- a/frameworks/Rust/ntex/Cargo.toml +++ b/frameworks/Rust/ntex/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "ntex" +name = "ntex-bench" version = "2.0.0" edition = "2018" @@ -8,7 +8,7 @@ name = "ntex" path = "src/main.rs" [[bin]] -name = "ntex-astd" +name = "ntex-compio" path = "src/main.rs" [[bin]] @@ -16,7 +16,7 @@ name = "ntex-db" path = "src/main_db.rs" [[bin]] -name = "ntex-db-astd" +name = "ntex-db-compio" path = "src/main_db.rs" [[bin]] @@ -24,7 +24,7 @@ name = "ntex-plt" path = "src/main_plt.rs" [[bin]] -name = "ntex-plt-astd" +name = "ntex-plt-compio" path = "src/main_plt.rs" [features] @@ -33,11 +33,11 @@ default = [] # tokio runtime tokio = ["ntex/tokio"] -# async-std runtime -async-std = ["ntex/async-std"] +# compio runtime +compio = ["ntex/compio"] [dependencies] -ntex = "=2.1.0" +ntex = "2.4" ntex-bytes = { version = "0.1.21", features=["simd"] } mimalloc = { version = "0.1.25", default-features = false } snmalloc-rs = { version = "0.3.3", features = ["native-cpu"] } @@ -63,3 +63,10 @@ lto = "thin" debug = false incremental = false overflow-checks = false + +[patch.crates-io] +ntex = { git = "https://github.com/ntex-rs/ntex.git", branch = "compio" } +ntex-io = { git = "https://github.com/ntex-rs/ntex.git", branch = "compio" } +ntex-rt = { git = "https://github.com/ntex-rs/ntex.git", branch = "compio" } +ntex-net = { git = "https://github.com/ntex-rs/ntex.git", branch = "compio" } +ntex-compio = { git = "https://github.com/ntex-rs/ntex.git", branch = "compio" } diff --git a/frameworks/Rust/ntex/benchmark_config.json b/frameworks/Rust/ntex/benchmark_config.json index ab6fc091970..9ed29c64b97 100755 --- a/frameworks/Rust/ntex/benchmark_config.json +++ b/frameworks/Rust/ntex/benchmark_config.json @@ -19,7 +19,7 @@ "notes": "", "versus": "" }, - "astd": { + "compio": { "json_url": "/json", "plaintext_url": "/plaintext", "port": 8080, @@ -33,7 +33,7 @@ "webserver": "ntex", "os": "Linux", "database_os": "Linux", - "display_name": "ntex [async-std]", + "display_name": "ntex [compio]", "notes": "", "versus": "" }, @@ -57,7 +57,7 @@ "notes": "", "versus": "" }, - "db-astd": { + "db-compio": { "fortune_url": "/fortunes", "db_url": "/db", "query_url": "/query?q=", @@ -73,7 +73,7 @@ "webserver": "ntex", "os": "Linux", "database_os": "Linux", - "display_name": "ntex [async-std,db]", + "display_name": "ntex [compio,db]", "notes": "", "versus": "" }, @@ -95,7 +95,7 @@ "notes": "", "versus": "" }, - "plt-astd": { + "plt-compio": { "json_url": "/json", "plaintext_url": "/plaintext", "port": 8080, @@ -109,7 +109,7 @@ "webserver": "ntex", "os": "Linux", "database_os": "Linux", - "display_name": "ntex [async-std,platform]", + "display_name": "ntex [compio,platform]", "notes": "", "versus": "" } diff --git a/frameworks/Rust/ntex/config.toml b/frameworks/Rust/ntex/config.toml index 84527c12626..759dca26c70 100644 --- a/frameworks/Rust/ntex/config.toml +++ b/frameworks/Rust/ntex/config.toml @@ -14,7 +14,7 @@ platform = "None" webserver = "ntex" versus = "" -[astd] +[compio] urls.plaintext = "/plaintext" urls.json = "/json" approach = "Realistic" @@ -42,7 +42,7 @@ platform = "None" webserver = "ntex" versus = "" -[db-astd] +[db-compio] urls.db = "/db" urls.query = "/query?q=" urls.update = "/update?q=" @@ -70,7 +70,7 @@ platform = "None" webserver = "ntex" versus = "" -[plt-astd] +[plt-compio] urls.plaintext = "/plaintext" urls.json = "/json" approach = "Realistic" diff --git a/frameworks/Rust/ntex/ntex-astd.dockerfile b/frameworks/Rust/ntex/ntex-compio.dockerfile similarity index 84% rename from frameworks/Rust/ntex/ntex-astd.dockerfile rename to frameworks/Rust/ntex/ntex-compio.dockerfile index be97758bbeb..c825e18078e 100644 --- a/frameworks/Rust/ntex/ntex-astd.dockerfile +++ b/frameworks/Rust/ntex/ntex-compio.dockerfile @@ -9,8 +9,8 @@ ADD ./ /ntex WORKDIR /ntex RUN cargo clean -RUN RUSTFLAGS="-C target-cpu=native" cargo build --release --features="async-std" +RUN RUSTFLAGS="-C target-cpu=native" cargo build --release --features="compio" EXPOSE 8080 -CMD ./target/release/ntex-astd +CMD ./target/release/ntex-compio diff --git a/frameworks/Rust/ntex/ntex-db-astd.dockerfile b/frameworks/Rust/ntex/ntex-db-compio.dockerfile similarity index 84% rename from frameworks/Rust/ntex/ntex-db-astd.dockerfile rename to frameworks/Rust/ntex/ntex-db-compio.dockerfile index e8717d37a50..c892bcdc9fc 100644 --- a/frameworks/Rust/ntex/ntex-db-astd.dockerfile +++ b/frameworks/Rust/ntex/ntex-db-compio.dockerfile @@ -9,8 +9,8 @@ ADD ./ /ntex WORKDIR /ntex RUN cargo clean -RUN RUSTFLAGS="-C target-cpu=native" cargo build --release --features="async-std" +RUN RUSTFLAGS="-C target-cpu=native" cargo build --release --features="compio" EXPOSE 8080 -CMD ./target/release/ntex-db-astd +CMD ./target/release/ntex-db-compio diff --git a/frameworks/Rust/ntex/ntex-plt-astd.dockerfile b/frameworks/Rust/ntex/ntex-plt-compio.dockerfile similarity index 83% rename from frameworks/Rust/ntex/ntex-plt-astd.dockerfile rename to frameworks/Rust/ntex/ntex-plt-compio.dockerfile index 8ec6c7fe636..849e224994b 100644 --- a/frameworks/Rust/ntex/ntex-plt-astd.dockerfile +++ b/frameworks/Rust/ntex/ntex-plt-compio.dockerfile @@ -9,8 +9,8 @@ ADD ./ /ntex WORKDIR /ntex RUN cargo clean -RUN RUSTFLAGS="-C target-cpu=native" cargo build --release --features="async-std" +RUN RUSTFLAGS="-C target-cpu=native" cargo build --release --features="compio" EXPOSE 8080 -CMD ./target/release/ntex-plt-astd +CMD ./target/release/ntex-plt-compio diff --git a/frameworks/Rust/ntex/src/main.rs b/frameworks/Rust/ntex/src/main.rs index c456fac47e4..218ed03c727 100644 --- a/frameworks/Rust/ntex/src/main.rs +++ b/frameworks/Rust/ntex/src/main.rs @@ -1,6 +1,5 @@ #[global_allocator] static GLOBAL: mimalloc::MiMalloc = mimalloc::MiMalloc; -// static GLOBAL: snmalloc_rs::SnMalloc = snmalloc_rs::SnMalloc; use ntex::http::header::{CONTENT_TYPE, SERVER}; use ntex::{http, time::Seconds, util::BytesMut, util::PoolId, web}; diff --git a/frameworks/Rust/ntex/src/main_plt.rs b/frameworks/Rust/ntex/src/main_plt.rs index 2f46ce448e1..b6c435f6773 100644 --- a/frameworks/Rust/ntex/src/main_plt.rs +++ b/frameworks/Rust/ntex/src/main_plt.rs @@ -1,5 +1,5 @@ #[global_allocator] -static GLOBAL: snmalloc_rs::SnMalloc = snmalloc_rs::SnMalloc; +static GLOBAL: mimalloc::MiMalloc = mimalloc::MiMalloc; use std::{future::Future, io, pin::Pin, task::Context, task::Poll}; From 98fb99ac99759e4d8deddf6f212bb7743019b1e6 Mon Sep 17 00:00:00 2001 From: Anton Kirilov Date: Mon, 26 Aug 2024 17:29:50 +0100 Subject: [PATCH 087/204] Revert "H2O: Use 2 database connections per thread again (#9176)" (#9223) This reverts commit 57f2f117488029a625feea0605f7da76bfb2a0b9. --- frameworks/C/h2o/h2o.dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frameworks/C/h2o/h2o.dockerfile b/frameworks/C/h2o/h2o.dockerfile index 3b383b7f6df..976c938337a 100644 --- a/frameworks/C/h2o/h2o.dockerfile +++ b/frameworks/C/h2o/h2o.dockerfile @@ -109,4 +109,4 @@ CMD ["taskset", \ "dbname=hello_world host=tfb-database password=benchmarkdbpass sslmode=disable user=benchmarkdbuser", \ "-f", \ "/opt/h2o_app/share/h2o_app/template", \ - "-m2"] + "-m1"] From 12ba6b9c5a8c54b6be540feead83dce7206d3def Mon Sep 17 00:00:00 2001 From: Yan Kun <1939810907@qq.com> Date: Tue, 27 Aug 2024 00:30:06 +0800 Subject: [PATCH 088/204] [Scala/otavia] upgrade otavia to 0.4.2 (#9224) * [Scala/otavia] upgrade otavia to 0.4.2 * [Scala/otavia] change randomnumber to randomNumber * [Scala/otavia] upgrade otavia to 0.4.3 --- .../Scala/otavia/{README.MD => README.md} | 0 .../src/app/controller/DBController.scala | 19 ++++---- .../app/controller/FortuneController.scala | 18 +++++-- .../benchmark/src/app/model/Fortune.scala | 4 +- .../benchmark/src/app/model/World.scala | 4 +- .../src/app/util/FortunesRender.scala | 6 +-- frameworks/Scala/otavia/benchmark_config.json | 48 ++++++++++++++++++- frameworks/Scala/otavia/build.sc | 2 +- frameworks/Scala/otavia/config.toml | 36 +++++++++++++- .../otavia-equalization-offgc.dockerfile | 16 +++++++ ...kerfile => otavia-equalization.dockerfile} | 4 +- .../Scala/otavia/otavia-offgc.dockerfile | 16 +++++++ frameworks/Scala/otavia/otavia.dockerfile | 4 +- 13 files changed, 148 insertions(+), 29 deletions(-) rename frameworks/Scala/otavia/{README.MD => README.md} (100%) create mode 100644 frameworks/Scala/otavia/otavia-equalization-offgc.dockerfile rename frameworks/Scala/otavia/{otavia-reserve.dockerfile => otavia-equalization.dockerfile} (76%) create mode 100644 frameworks/Scala/otavia/otavia-offgc.dockerfile diff --git a/frameworks/Scala/otavia/README.MD b/frameworks/Scala/otavia/README.md similarity index 100% rename from frameworks/Scala/otavia/README.MD rename to frameworks/Scala/otavia/README.md diff --git a/frameworks/Scala/otavia/benchmark/src/app/controller/DBController.scala b/frameworks/Scala/otavia/benchmark/src/app/controller/DBController.scala index 6b54504aecc..2e9e32abbe7 100644 --- a/frameworks/Scala/otavia/benchmark/src/app/controller/DBController.scala +++ b/frameworks/Scala/otavia/benchmark/src/app/controller/DBController.scala @@ -9,7 +9,7 @@ import cc.otavia.core.stack.helper.{FutureState, FuturesState, StartState} import cc.otavia.core.stack.{AskStack, StackState, StackYield} import cc.otavia.http.server.{HttpRequest, HttpResponse} import cc.otavia.sql.Connection -import cc.otavia.sql.Statement.{ModifyRows, PrepareQuery} +import cc.otavia.sql.statement.{ModifyRows, PrepareQuery} import java.util.SplittableRandom @@ -22,20 +22,17 @@ class DBController extends StateActor[REQ] { override protected def afterMount(): Unit = connection = autowire[Connection]() override protected def resumeAsk(stack: AskStack[REQ & Ask[? <: Reply]]): StackYield = - stack match - case stack: AskStack[SingleQueryRequest] if stack.ask.isInstanceOf[SingleQueryRequest] => - handleSingleQuery(stack) - case stack: AskStack[MultipleQueryRequest] if stack.ask.isInstanceOf[MultipleQueryRequest] => - handleMultipleQuery(stack) - case stack: AskStack[UpdateRequest] if stack.ask.isInstanceOf[UpdateRequest] => - handleUpdateQuery(stack) + stack.ask match + case _: SingleQueryRequest => handleSingleQuery(stack.asInstanceOf[AskStack[SingleQueryRequest]]) + case _: MultipleQueryRequest => handleMultipleQuery(stack.asInstanceOf[AskStack[MultipleQueryRequest]]) + case _: UpdateRequest => handleUpdateQuery(stack.asInstanceOf[AskStack[UpdateRequest]]) // Test 2: Single database query private def handleSingleQuery(stack: AskStack[SingleQueryRequest]): StackYield = { stack.state match case _: StartState => val state = FutureState[World]() - connection.ask(PrepareQuery.fetchOne[World](SELECT_WORLD, Tuple1(randomWorld())), state.future) + connection.ask(PrepareQuery.fetchOne[World](SELECT_WORLD, randomWorld()), state.future) stack.suspend(state) case state: FutureState[World] => stack.`return`(state.future.getNow) @@ -61,7 +58,7 @@ class DBController extends StateActor[REQ] { stack.attach(worlds) val newState = FutureState[ModifyRows]() val newWorlds = worlds.sortBy(_.id).map(_.copy(randomNumber = randomWorld())) - connection.ask(PrepareQuery.update(UPDATE_WORLD, newWorlds), newState.future) + connection.ask(PrepareQuery.updateBatch(UPDATE_WORLD, newWorlds), newState.future) stack.suspend(newState) case state: FutureState[ModifyRows] => if (state.future.isFailed) state.future.causeUnsafe.printStackTrace() @@ -72,7 +69,7 @@ class DBController extends StateActor[REQ] { private def selectWorlds(queries: Int): StackState = { val state = FuturesState[World](queries) for (future <- state.futures) - connection.ask(PrepareQuery.fetchOne[World](SELECT_WORLD, Tuple1(randomWorld())), future) + connection.ask(PrepareQuery.fetchOne[World](SELECT_WORLD, randomWorld()), future) state } diff --git a/frameworks/Scala/otavia/benchmark/src/app/controller/FortuneController.scala b/frameworks/Scala/otavia/benchmark/src/app/controller/FortuneController.scala index 05ff8c468ba..4f7fe7bf800 100644 --- a/frameworks/Scala/otavia/benchmark/src/app/controller/FortuneController.scala +++ b/frameworks/Scala/otavia/benchmark/src/app/controller/FortuneController.scala @@ -7,12 +7,20 @@ import cc.otavia.core.address.Address import cc.otavia.core.stack.helper.{FutureState, StartState} import cc.otavia.core.stack.{AskStack, StackState, StackYield} import cc.otavia.http.server.{HttpRequest, HttpResponse} -import cc.otavia.sql.Statement.PrepareQuery +import cc.otavia.sql.statement.PrepareQuery import cc.otavia.sql.{Connection, RowSet} +import java.util +import java.util.Comparator + class FortuneController extends StateActor[FortuneRequest] { private var connection: Address[MessageOf[Connection]] = _ + private val tmpArray: Array[Fortune] = new Array[Fortune](13) + + private val comparator = new Comparator[Fortune] { + override def compare(o1: Fortune, o2: Fortune): Int = o1.message.compareTo(o2.message) + } override protected def afterMount(): Unit = connection = autowire[Connection]() @@ -24,8 +32,10 @@ class FortuneController extends StateActor[FortuneRequest] { connection.ask(PrepareQuery.fetchAll[Fortune](SELECT_FORTUNE), state.future) stack.suspend(state) case state: FutureState[RowSet[Fortune]] => - val fortunes = (state.future.getNow.rows :+ Fortune(0, "Additional fortune added at request time.")) - .sortBy(_.message) + System.arraycopy(state.future.getNow.rows, 0, tmpArray, 0, 12) + tmpArray(12) = Fortune(0, "Additional fortune added at request time.") + util.Arrays.sort(tmpArray, comparator) + val fortunes = tmpArray.clone() val response = HttpResponse.builder.setContent(fortunes).build() stack.`return`(response) } @@ -34,7 +44,7 @@ class FortuneController extends StateActor[FortuneRequest] { object FortuneController { - class FortuneRequest extends HttpRequest[Nothing, HttpResponse[Seq[Fortune]]] + class FortuneRequest extends HttpRequest[Nothing, HttpResponse[Array[Fortune]]] private val SELECT_FORTUNE = "SELECT id, message from FORTUNE" diff --git a/frameworks/Scala/otavia/benchmark/src/app/model/Fortune.scala b/frameworks/Scala/otavia/benchmark/src/app/model/Fortune.scala index edb58d3cdc9..1df592954a4 100644 --- a/frameworks/Scala/otavia/benchmark/src/app/model/Fortune.scala +++ b/frameworks/Scala/otavia/benchmark/src/app/model/Fortune.scala @@ -1,7 +1,7 @@ package app.model import cc.otavia.json.JsonSerde -import cc.otavia.sql.{Row, RowDecoder} +import cc.otavia.sql.{Row, RowCodec} /** The model for the "fortune" database table. */ -case class Fortune(id: Int, message: String) extends Row derives RowDecoder, JsonSerde +case class Fortune(id: Int, message: String) extends Row derives RowCodec, JsonSerde diff --git a/frameworks/Scala/otavia/benchmark/src/app/model/World.scala b/frameworks/Scala/otavia/benchmark/src/app/model/World.scala index a0e6f6056f8..af6f8539d74 100644 --- a/frameworks/Scala/otavia/benchmark/src/app/model/World.scala +++ b/frameworks/Scala/otavia/benchmark/src/app/model/World.scala @@ -2,7 +2,7 @@ package app.model import cc.otavia.json.JsonSerde import cc.otavia.serde.annotation.rename -import cc.otavia.sql.{Row, RowDecoder} +import cc.otavia.sql.{Row, RowCodec} /** The model for the "world" database table. */ -case class World(id: Int, @rename("randomnumber") randomNumber: Int) extends Row derives RowDecoder, JsonSerde +case class World(id: Int, randomNumber: Int) extends Row derives RowCodec, JsonSerde diff --git a/frameworks/Scala/otavia/benchmark/src/app/util/FortunesRender.scala b/frameworks/Scala/otavia/benchmark/src/app/util/FortunesRender.scala index 0c0694ee836..69401305550 100644 --- a/frameworks/Scala/otavia/benchmark/src/app/util/FortunesRender.scala +++ b/frameworks/Scala/otavia/benchmark/src/app/util/FortunesRender.scala @@ -7,7 +7,7 @@ import cc.otavia.serde.Serde import java.nio.charset.StandardCharsets import scala.annotation.switch -class FortunesRender extends Serde[Seq[Fortune]] { +class FortunesRender extends Serde[Array[Fortune]] { private val text1 = "Fortunes" @@ -27,7 +27,7 @@ class FortunesRender extends Serde[Seq[Fortune]] { private val squot = "'".getBytes() private val amp = "&".getBytes() - override def serialize(fortunes: Seq[Fortune], out: Buffer): Unit = { + override def serialize(fortunes: Array[Fortune], out: Buffer): Unit = { out.writeBytes(text1) for (fortune <- fortunes) { out.writeBytes(text2) @@ -39,7 +39,7 @@ class FortunesRender extends Serde[Seq[Fortune]] { out.writeBytes(text5) } - override def deserialize(in: Buffer): Seq[Fortune] = throw new UnsupportedOperationException() + override def deserialize(in: Buffer): Array[Fortune] = throw new UnsupportedOperationException() private def writeEscapeMessage(buffer: Buffer, message: String): Unit = { var i = 0 diff --git a/frameworks/Scala/otavia/benchmark_config.json b/frameworks/Scala/otavia/benchmark_config.json index ae712574778..a93a000f3b4 100644 --- a/frameworks/Scala/otavia/benchmark_config.json +++ b/frameworks/Scala/otavia/benchmark_config.json @@ -25,7 +25,53 @@ "notes": "", "versus": "Otavia" }, - "reserve": { + "equalization": { + "json_url": "/json", + "plaintext_url": "/plaintext", + "db_url": "/db", + "query_url": "/queries?queries=", + "fortune_url": "/fortunes", + "update_url": "/updates?queries=", + "port": 8080, + "approach": "Realistic", + "classification": "Micro", + "database": "Postgres", + "framework": "otavia", + "language": "Scala", + "flavor": "None", + "orm": "Micro", + "platform": "Otavia", + "webserver": "None", + "os": "Linux", + "database_os": "Linux", + "display_name": "otavia", + "notes": "", + "versus": "Otavia" + }, + "equalization-offgc": { + "json_url": "/json", + "plaintext_url": "/plaintext", + "db_url": "/db", + "query_url": "/queries?queries=", + "fortune_url": "/fortunes", + "update_url": "/updates?queries=", + "port": 8080, + "approach": "Realistic", + "classification": "Micro", + "database": "Postgres", + "framework": "otavia", + "language": "Scala", + "flavor": "None", + "orm": "Micro", + "platform": "Otavia", + "webserver": "None", + "os": "Linux", + "database_os": "Linux", + "display_name": "otavia", + "notes": "", + "versus": "Otavia" + }, + "offgc": { "json_url": "/json", "plaintext_url": "/plaintext", "db_url": "/db", diff --git a/frameworks/Scala/otavia/build.sc b/frameworks/Scala/otavia/build.sc index 2b7877b7891..7f872fdf851 100644 --- a/frameworks/Scala/otavia/build.sc +++ b/frameworks/Scala/otavia/build.sc @@ -1,7 +1,7 @@ import mill._ import mill.scalalib._ -def otaviaVersion = "0.4.0" +def otaviaVersion = "0.4.3" object benchmark extends ScalaModule { diff --git a/frameworks/Scala/otavia/config.toml b/frameworks/Scala/otavia/config.toml index 96613dfd2fd..9443c4d261b 100644 --- a/frameworks/Scala/otavia/config.toml +++ b/frameworks/Scala/otavia/config.toml @@ -18,7 +18,7 @@ platform = "Otavia" webserver = "None" versus = "Otavia" -[reserve] +[equalization] urls.plaintext = "/plaintext" urls.json = "/json" urls.db = "/db" @@ -34,3 +34,37 @@ orm = "Micro" platform = "Otavia" webserver = "None" versus = "Otavia" + +[equalization-offgc] +urls.plaintext = "/plaintext" +urls.json = "/json" +urls.db = "/db" +urls.query = "/queries?queries=" +urls.update = "/updates?queries=" +urls.fortune = "/fortunes" +approach = "Realistic" +classification = "Micro" +database = "Postgres" +database_os = "Linux" +os = "Linux" +orm = "Micro" +platform = "Otavia" +webserver = "None" +versus = "Otavia" + +[offgc] +urls.plaintext = "/plaintext" +urls.json = "/json" +urls.db = "/db" +urls.query = "/queries?queries=" +urls.update = "/updates?queries=" +urls.fortune = "/fortunes" +approach = "Realistic" +classification = "Micro" +database = "Postgres" +database_os = "Linux" +os = "Linux" +orm = "Micro" +platform = "Otavia" +webserver = "None" +versus = "Otavia" \ No newline at end of file diff --git a/frameworks/Scala/otavia/otavia-equalization-offgc.dockerfile b/frameworks/Scala/otavia/otavia-equalization-offgc.dockerfile new file mode 100644 index 00000000000..23c9a90fd9e --- /dev/null +++ b/frameworks/Scala/otavia/otavia-equalization-offgc.dockerfile @@ -0,0 +1,16 @@ +FROM nightscape/scala-mill:eclipse-temurin-17.0.8.1_1-jdk-focal_0.11.6_3.3.0 +WORKDIR /otavia +COPY benchmark benchmark +COPY build.sc build.sc +ENV COURSIER_REPOSITORIES=ivy2Local|central +RUN mill benchmark.assembly + +EXPOSE 8080 + +CMD java -server \ + -Dcc.otavia.actor.worker.size=56 -Dcc.otavia.nio.worker.size=56 \ + -Dcc.otavia.system.gc.aggressive=false \ + -jar \ + out/benchmark/assembly.dest/out.jar \ + jdbc:postgresql://tfb-database:5432/hello_world \ + benchmarkdbuser benchmarkdbpass 56 diff --git a/frameworks/Scala/otavia/otavia-reserve.dockerfile b/frameworks/Scala/otavia/otavia-equalization.dockerfile similarity index 76% rename from frameworks/Scala/otavia/otavia-reserve.dockerfile rename to frameworks/Scala/otavia/otavia-equalization.dockerfile index 5768000706e..780aeafe0b0 100644 --- a/frameworks/Scala/otavia/otavia-reserve.dockerfile +++ b/frameworks/Scala/otavia/otavia-equalization.dockerfile @@ -8,8 +8,8 @@ RUN mill benchmark.assembly EXPOSE 8080 CMD java -server \ - -Dcc.otavia.actor.worker.size=18 -Dcc.otavia.nio.worker.size=36 \ + -Dcc.otavia.actor.worker.size=56 -Dcc.otavia.nio.worker.size=56 \ -jar \ out/benchmark/assembly.dest/out.jar \ jdbc:postgresql://tfb-database:5432/hello_world \ - benchmarkdbuser benchmarkdbpass 54 + benchmarkdbuser benchmarkdbpass 56 diff --git a/frameworks/Scala/otavia/otavia-offgc.dockerfile b/frameworks/Scala/otavia/otavia-offgc.dockerfile new file mode 100644 index 00000000000..378a48dd2f9 --- /dev/null +++ b/frameworks/Scala/otavia/otavia-offgc.dockerfile @@ -0,0 +1,16 @@ +FROM nightscape/scala-mill:eclipse-temurin-17.0.8.1_1-jdk-focal_0.11.6_3.3.0 +WORKDIR /otavia +COPY benchmark benchmark +COPY build.sc build.sc +ENV COURSIER_REPOSITORIES=ivy2Local|central +RUN mill benchmark.assembly + +EXPOSE 8080 + +CMD java -server \ + -Dcc.otavia.actor.worker.size=28 -Dcc.otavia.nio.worker.size=56 \ + -Dcc.otavia.system.gc.aggressive=false \ + -jar \ + out/benchmark/assembly.dest/out.jar \ + jdbc:postgresql://tfb-database:5432/hello_world \ + benchmarkdbuser benchmarkdbpass 56 diff --git a/frameworks/Scala/otavia/otavia.dockerfile b/frameworks/Scala/otavia/otavia.dockerfile index c1c944d60aa..e407df7ad79 100644 --- a/frameworks/Scala/otavia/otavia.dockerfile +++ b/frameworks/Scala/otavia/otavia.dockerfile @@ -8,8 +8,8 @@ RUN mill benchmark.assembly EXPOSE 8080 CMD java -server \ - -Dcc.otavia.actor.worker.size=24 -Dcc.otavia.nio.worker.size=48 \ + -Dcc.otavia.actor.worker.size=28 -Dcc.otavia.nio.worker.size=56 \ -jar \ out/benchmark/assembly.dest/out.jar \ jdbc:postgresql://tfb-database:5432/hello_world \ - benchmarkdbuser benchmarkdbpass 72 + benchmarkdbuser benchmarkdbpass 56 From 8d455d57e1eb293f7959b93bead6102df9e19403 Mon Sep 17 00:00:00 2001 From: fakeshadow <24548779@qq.com> Date: Wed, 28 Aug 2024 01:58:12 +0800 Subject: [PATCH 089/204] [xitca-web] fix wasi build. (#9225) * [xitca-web] fix wasi build. * fix config json. --- frameworks/Rust/xitca-web/Cargo.lock | 60 +++++++------- frameworks/Rust/xitca-web/Cargo.toml | 3 +- .../Rust/xitca-web/benchmark_config.json | 3 +- frameworks/Rust/xitca-web/src/db.rs | 78 +++++++++++-------- frameworks/Rust/xitca-web/src/db_diesel.rs | 6 +- frameworks/Rust/xitca-web/src/main.rs | 2 +- frameworks/Rust/xitca-web/src/main_iou.rs | 3 +- frameworks/Rust/xitca-web/src/main_sync.rs | 7 +- .../Rust/xitca-web/xitca-web-wasm.dockerfile | 2 +- 9 files changed, 93 insertions(+), 71 deletions(-) diff --git a/frameworks/Rust/xitca-web/Cargo.lock b/frameworks/Rust/xitca-web/Cargo.lock index e510a6c31dc..01bd80ec5e3 100644 --- a/frameworks/Rust/xitca-web/Cargo.lock +++ b/frameworks/Rust/xitca-web/Cargo.lock @@ -149,9 +149,12 @@ checksum = "8318a53db07bb3f8dca91a600466bdb3f2eaadeedfdbcf02e1accbad9271ba50" [[package]] name = "cc" -version = "1.1.8" +version = "1.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "504bdec147f2cc13c8b57ed9401fd8a147cc66b67ad5cb241394244f2c947549" +checksum = "72db2f7947ecee9b03b510377e8bb9077afa27176fdbff55c51027e976fdcc48" +dependencies = [ + "shlex", +] [[package]] name = "cfg-if" @@ -161,9 +164,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "cpufeatures" -version = "0.2.12" +version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" +checksum = "51e852e6dc9a5bed1fae92dd2375037bf2b768725bf3be87811edee3249d09ad" dependencies = [ "libc", ] @@ -471,9 +474,9 @@ checksum = "9028f49264629065d057f340a86acb84867925865f73bbf8d47b4d149a7e88b8" [[package]] name = "libc" -version = "0.2.155" +version = "0.2.158" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" +checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439" [[package]] name = "libmimalloc-sys" @@ -560,9 +563,8 @@ dependencies = [ [[package]] name = "mio" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4569e456d394deccd22ce1c1913e6ea0e54519f577285001215d33557431afe4" +version = "1.0.2" +source = "git+https://github.com/fakeshadow/mio?rev=9bae6012b7ecfc6083350785f71a5e8265358178#9bae6012b7ecfc6083350785f71a5e8265358178" dependencies = [ "hermit-abi", "libc", @@ -847,18 +849,18 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "serde" -version = "1.0.205" +version = "1.0.208" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e33aedb1a7135da52b7c21791455563facbbcc43d0f0f66165b42c21b3dfb150" +checksum = "cff085d2cb684faa248efb494c39b68e522822ac0de72ccf08109abde717cfb2" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.205" +version = "1.0.208" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "692d6f5ac90220161d6774db30c662202721e64aed9058d2c394f451261420c1" +checksum = "24008e81ff7613ed8e5ba0cfaf24e2c2f1e5b8a0495711e44fcd4882fca62bcf" dependencies = [ "proc-macro2", "quote", @@ -867,9 +869,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.122" +version = "1.0.125" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "784b6203951c57ff748476b126ccb5e8e2959a5c19e5c617ab1956be3dbc68da" +checksum = "83c8e735a073ccf5be70aa8066aa984eaf2fa000db6c8d0100ae605b366d31ed" dependencies = [ "itoa", "memchr", @@ -910,6 +912,12 @@ dependencies = [ "digest", ] +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + [[package]] name = "signal-hook-registry" version = "1.4.2" @@ -979,9 +987,9 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "syn" -version = "2.0.72" +version = "2.0.75" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc4b9b9bf2add8093d3f2c0204471e951b2285580335de42f9d2534f3ae7a8af" +checksum = "f6af063034fc1935ede7be0122941bafa9bacb949334d090b77ca98b5817c7d9" dependencies = [ "proc-macro2", "quote", @@ -1017,9 +1025,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.39.2" +version = "1.39.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "daa4fb1bc778bd6f04cbfc4bb2d06a7396a8f299dc33ea1900cedaa316f467b1" +checksum = "9babc99b9923bfa4804bd74722ff02c0381021eafa4db9949217e3be8e84fff5" dependencies = [ "backtrace", "libc", @@ -1079,15 +1087,15 @@ dependencies = [ [[package]] name = "tower-layer" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c20c8dbed6283a09604c3e69b4b7eeb54e298b8a600d4d5ecb5ad39de609f1d0" +checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" [[package]] name = "tower-service" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" +checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" [[package]] name = "tracing" @@ -1138,9 +1146,9 @@ dependencies = [ [[package]] name = "unicode-properties" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4259d9d4425d9f0661581b804cb85fe66a4c631cadd8f490d1c13a35d5d9291" +checksum = "52ea75f83c0137a9b98608359a5f1af8144876eb67bcb1ce837368e906a9f524" [[package]] name = "vcpkg" @@ -1311,7 +1319,7 @@ dependencies = [ [[package]] name = "xitca-postgres" version = "0.1.0" -source = "git+https://github.com/HFQR/xitca-web.git?rev=0cad5309beb278dc967378a35b733e26be0d4073#0cad5309beb278dc967378a35b733e26be0d4073" +source = "git+https://github.com/HFQR/xitca-web.git?rev=f4e7bed#f4e7bedfb441897d1f26a6e4d8cbfada23953269" dependencies = [ "fallible-iterator", "percent-encoding", diff --git a/frameworks/Rust/xitca-web/Cargo.toml b/frameworks/Rust/xitca-web/Cargo.toml index d9606bf2a96..e4614eb0bab 100644 --- a/frameworks/Rust/xitca-web/Cargo.toml +++ b/frameworks/Rust/xitca-web/Cargo.toml @@ -95,4 +95,5 @@ codegen-units = 1 panic = "abort" [patch.crates-io] -xitca-postgres = { git = "https://github.com/HFQR/xitca-web.git", rev = "0cad5309beb278dc967378a35b733e26be0d4073" } +xitca-postgres = { git = "https://github.com/HFQR/xitca-web.git", rev = "f4e7bed" } +mio = { git = "https://github.com/fakeshadow/mio", rev = "9bae6012b7ecfc6083350785f71a5e8265358178" } diff --git a/frameworks/Rust/xitca-web/benchmark_config.json b/frameworks/Rust/xitca-web/benchmark_config.json index 5371bcd2551..f4c152eb729 100755 --- a/frameworks/Rust/xitca-web/benchmark_config.json +++ b/frameworks/Rust/xitca-web/benchmark_config.json @@ -62,8 +62,7 @@ "database_os": "linux", "display_name": "xitca-web [wasm]", "notes": "", - "versus": "", - "tags": ["broken"] + "versus": "" }, "axum": { "json_url": "/json", diff --git a/frameworks/Rust/xitca-web/src/db.rs b/frameworks/Rust/xitca-web/src/db.rs index 755dfaacf70..aa783e29dce 100644 --- a/frameworks/Rust/xitca-web/src/db.rs +++ b/frameworks/Rust/xitca-web/src/db.rs @@ -1,9 +1,9 @@ -use std::{collections::HashMap, fmt::Write}; +use std::fmt::Write; +use xitca_io::bytes::BytesMut; use xitca_postgres::{ pipeline::Pipeline, statement::Statement, AsyncLendingIterator, SharedClient, }; -use xitca_unsafe_collection::no_hash::NoHashBuilder; use super::{ ser::{Fortune, Fortunes, World}, @@ -13,14 +13,16 @@ use super::{ pub struct Client { client: SharedClient, #[cfg(not(feature = "pg-sync"))] - rng: std::cell::RefCell, + shared: std::cell::RefCell, #[cfg(feature = "pg-sync")] - rng: std::sync::Mutex, + shared: std::sync::Mutex, fortune: Statement, world: Statement, - updates: HashMap, + updates: Box<[Statement]>, } +type Shared = (Rand, BytesMut); + pub async fn create() -> HandleResult { let mut client = SharedClient::new(DB_URL.to_string()).await?; @@ -30,7 +32,11 @@ pub async fn create() -> HandleResult { .prepare_cached("SELECT * FROM world WHERE id=$1", &[]) .await?; - let mut updates = HashMap::default(); + let mut updates = Vec::new(); + + // a dummy statement as placeholder of 0 index. + // avoid off by one calculation when using non zero u16 as slicing index. + updates.push(Statement::default()); for num in 1..=500u16 { let mut pl = 1; @@ -49,34 +55,36 @@ pub async fn create() -> HandleResult { q.push(')'); let st = client.prepare_cached(&q, &[]).await?; - updates.insert(num, st); + updates.push(st); } + let shared = (Rand::default(), BytesMut::new()); + Ok(Client { client, #[cfg(not(feature = "pg-sync"))] - rng: std::cell::RefCell::new(Rand::default()), + shared: std::cell::RefCell::new(shared), #[cfg(feature = "pg-sync")] - rng: std::sync::Mutex::new(Rand::default()), + shared: std::sync::Mutex::new(shared), fortune, world, - updates, + updates: updates.into_boxed_slice(), }) } impl Client { #[cfg(not(feature = "pg-sync"))] - fn borrow_rng_mut(&self) -> std::cell::RefMut<'_, Rand> { - self.rng.borrow_mut() + fn shared(&self) -> std::cell::RefMut<'_, Shared> { + self.shared.borrow_mut() } #[cfg(feature = "pg-sync")] - fn borrow_rng_mut(&self) -> std::sync::MutexGuard<'_, Rand> { - self.rng.lock().unwrap() + fn shared(&self) -> std::sync::MutexGuard<'_, Shared> { + self.shared.lock().unwrap() } pub async fn get_world(&self) -> HandleResult { - let id = self.borrow_rng_mut().gen_id(); + let id = self.shared().0.gen_id(); self.client .query_raw(&self.world, [id]) .await? @@ -87,17 +95,21 @@ impl Client { } pub async fn get_worlds(&self, num: u16) -> HandleResult> { - let mut pipe = Pipeline::new(); + let len = num as usize; + + let mut res = { + let (ref mut rng, ref mut buf) = *self.shared(); + + let mut pipe = Pipeline::<_, false>::with_capacity_from_buf(len, buf); - { - let mut rng = self.borrow_rng_mut(); (0..num).try_for_each(|_| pipe.query_raw(&self.world, [rng.gen_id()]))?; + + self.client.pipeline(pipe) } + .await?; - let mut worlds = Vec::new(); - worlds.reserve(num as usize); + let mut worlds = Vec::with_capacity(len); - let mut res = self.client.pipeline(pipe).await?; while let Some(mut item) = res.try_next().await? { while let Some(row) = item.try_next().await? { worlds.push(World::new(row.get_raw(0), row.get_raw(1))) @@ -113,27 +125,31 @@ impl Client { let mut params = Vec::new(); params.reserve(len * 3); - let mut pipe = Pipeline::new(); + let mut res = { + let (ref mut rng, ref mut buf) = *self.shared(); + + let mut pipe = Pipeline::<_, false>::with_capacity_from_buf(len + 1, buf); - { - let mut rng = self.borrow_rng_mut(); (0..num).try_for_each(|_| { let w_id = rng.gen_id(); let r_id = rng.gen_id(); params.extend([w_id, r_id]); pipe.query_raw(&self.world, [w_id]) })?; - } - params.extend_from_within(..len); - let st = self.updates.get(&num).unwrap(); - pipe.query_raw(st, ¶ms)?; + params.extend_from_within(..len); + + let st = self.updates.get(len).unwrap(); + pipe.query_raw(st, ¶ms)?; + + self.client.pipeline(pipe) + } + .await?; let mut worlds = Vec::new(); worlds.reserve(len); let mut r_ids = params.into_iter().skip(1).step_by(2); - let mut res = self.client.pipeline(pipe).await?; while let Some(mut item) = res.try_next().await? { while let Some(row) = item.try_next().await? { let r_id = r_ids.next().unwrap(); @@ -148,8 +164,8 @@ impl Client { let mut items = Vec::with_capacity(32); items.push(Fortune::new(0, "Additional fortune added at request time.")); - let mut stream = self.client.query_raw::<[i32; 0]>(&self.fortune, []).await?; - while let Some(row) = stream.try_next().await? { + let mut res = self.client.query_raw::<[i32; 0]>(&self.fortune, []).await?; + while let Some(row) = res.try_next().await? { items.push(Fortune::new(row.get_raw(0), row.get_raw::(1))); } items.sort_by(|it, next| it.message.cmp(&next.message)); diff --git a/frameworks/Rust/xitca-web/src/db_diesel.rs b/frameworks/Rust/xitca-web/src/db_diesel.rs index 49a3e158e18..79ba4c9a69a 100644 --- a/frameworks/Rust/xitca-web/src/db_diesel.rs +++ b/frameworks/Rust/xitca-web/src/db_diesel.rs @@ -16,8 +16,8 @@ pub struct _Pool { pub fn create() -> std::io::Result> { r2d2::Builder::new() - .max_size(256) - .min_idle(Some(256)) + .max_size(100) + .min_idle(Some(100)) .test_on_check_out(false) .idle_timeout(None) .max_lifetime(None) @@ -34,7 +34,7 @@ pub fn create() -> std::io::Result> { #[cold] #[inline(never)] fn not_found() -> Error { - format!("world not found").into() + "world not found".into() } impl _Pool { diff --git a/frameworks/Rust/xitca-web/src/main.rs b/frameworks/Rust/xitca-web/src/main.rs index 632504dac5e..8405c986717 100755 --- a/frameworks/Rust/xitca-web/src/main.rs +++ b/frameworks/Rust/xitca-web/src/main.rs @@ -53,7 +53,7 @@ where async fn plain_text(ctx: Ctx<'_>) -> HandleResult { let (req, _) = ctx.into_parts(); - let mut res = req.into_response(Bytes::from_static(b"Hello, World!")); + let mut res = req.into_response(const { Bytes::from_static(b"Hello, World!") }); res.headers_mut().insert(CONTENT_TYPE, TEXT); Ok(res) } diff --git a/frameworks/Rust/xitca-web/src/main_iou.rs b/frameworks/Rust/xitca-web/src/main_iou.rs index 67ae6dad4d3..8ca722f1fbe 100644 --- a/frameworks/Rust/xitca-web/src/main_iou.rs +++ b/frameworks/Rust/xitca-web/src/main_iou.rs @@ -57,8 +57,7 @@ async fn handler(ctx: Ctx<'_, Request>) -> Result { let (req, state) = ctx.into_parts(); let mut res = match req.uri().path() { "/plaintext" => { - const HELLO: Bytes = Bytes::from_static(b"Hello, World!"); - let mut res = req.into_response(HELLO); + let mut res = req.into_response(const { Bytes::from_static(b"Hello, World!") }); res.headers_mut().insert(CONTENT_TYPE, TEXT); res } diff --git a/frameworks/Rust/xitca-web/src/main_sync.rs b/frameworks/Rust/xitca-web/src/main_sync.rs index 03f6c9ea3a3..cf36166ac70 100644 --- a/frameworks/Rust/xitca-web/src/main_sync.rs +++ b/frameworks/Rust/xitca-web/src/main_sync.rs @@ -27,6 +27,7 @@ fn main() -> std::io::Result<()> { .at_typed(updates) .map(header) .serve() + .disable_vectored_write() .bind("0.0.0.0:8080")? .run() .wait() @@ -45,10 +46,8 @@ fn db(StateOwn(pool): StateOwn) -> HandleResult> { #[route("/fortunes", method = get)] fn fortunes(StateOwn(pool): StateOwn) -> HandleResult> { use sailfish::TemplateOnce; - pool.tell_fortune()? - .render_once() - .map(Html) - .map_err(Into::into) + let html = pool.tell_fortune()?.render_once()?; + Ok(Html(html)) } #[route("/queries", method = get)] diff --git a/frameworks/Rust/xitca-web/xitca-web-wasm.dockerfile b/frameworks/Rust/xitca-web/xitca-web-wasm.dockerfile index 51aa96fd4eb..02634638c16 100644 --- a/frameworks/Rust/xitca-web/xitca-web-wasm.dockerfile +++ b/frameworks/Rust/xitca-web/xitca-web-wasm.dockerfile @@ -1,7 +1,7 @@ ARG WASMTIME_VERSION=15.0.0 ARG WASM_TARGET=wasm32-wasip1-threads -FROM rust:1.77 AS compile +FROM rust:1.79 AS compile ARG WASMTIME_VERSION ARG WASM_TARGET From 33044001ca026e7fb2652d5deb2cbda4d19a0358 Mon Sep 17 00:00:00 2001 From: MARiA so cute <33935209+NathanFreeman@users.noreply.github.com> Date: Wed, 28 Aug 2024 01:58:27 +0800 Subject: [PATCH 090/204] [PHP]update swoole version to 5.1.4 (#9229) * update swoole version to 5.1.4 * update container to 24.04 * cache statement for coroutine type --- frameworks/PHP/swoole/database.php | 112 ++++++++++++------ frameworks/PHP/swoole/php.ini | 2 +- .../PHP/swoole/swoole-async-mysql.dockerfile | 6 +- .../swoole/swoole-async-postgres.dockerfile | 6 +- frameworks/PHP/swoole/swoole-server.php | 14 ++- .../PHP/swoole/swoole-sync-mysql.dockerfile | 6 +- .../swoole/swoole-sync-postgres.dockerfile | 6 +- 7 files changed, 96 insertions(+), 56 deletions(-) diff --git a/frameworks/PHP/swoole/database.php b/frameworks/PHP/swoole/database.php index 6a7cdb3c1ea..19aac390968 100644 --- a/frameworks/PHP/swoole/database.php +++ b/frameworks/PHP/swoole/database.php @@ -21,14 +21,14 @@ public static function db(PDOStatement|PDOStatementProxy $db): string public static function fortunes(PDOStatement|PDOStatementProxy $fortune): string { $fortune->execute(); - $results = $fortune->fetchAll(PDO::FETCH_KEY_PAIR); + $results = $fortune->fetchAll(PDO::FETCH_KEY_PAIR); $results[0] = 'Additional fortune added at request time.'; asort($results); $html = ''; foreach ($results as $id => $message) { $message = htmlspecialchars($message, ENT_QUOTES, 'UTF-8'); - $html .= ""; + $html .= ""; } return "Fortunes
idmessage
$id$message
$id$message
$html
idmessage
"; @@ -36,13 +36,8 @@ public static function fortunes(PDOStatement|PDOStatementProxy $fortune): string public static function query(PDOStatement|PDOStatementProxy $query, int $queries): string { - $query_count = 1; - if ($queries > 1) { - $query_count = min($queries, 500); - } - $results = []; - while ($query_count--) { + while ($queries--) { $query->execute([mt_rand(1, 10000)]); $results[] = $query->fetch(PDO::FETCH_ASSOC); } @@ -50,33 +45,38 @@ public static function query(PDOStatement|PDOStatementProxy $query, int $queries return json_encode($results, JSON_NUMERIC_CHECK); } - public static function updates(PDOStatement|PDOStatementProxy $random, PDOStatement|PDOStatementProxy $update, int $queries): string + public static function updates(PDOStatement|PDOStatementProxy $random, PDOStatement|PDOStatementProxy $update, int $queries, string $driver): string { - $query_count = 1; - if ($queries > 1) { - $query_count = min($queries, 500); - } - - $results = []; - while ($query_count--) { - $id = mt_rand(1, 10000); - $random->execute([$id]); - $item = $random->fetch(PDO::FETCH_ASSOC); - $update->execute([$item['randomNumber'] = mt_rand(1, 10000), $id]); + $results = $keys = $values = []; + while ($queries--) { + $random->execute([mt_rand(1, 10000)]); + $item = $random->fetch(PDO::FETCH_ASSOC); + $item['randomNumber'] = mt_rand(1, 10000); + $results[] = $item; - $results[] = $item; + if ($driver == 'pgsql') { + $values[] = $keys[] = $item['id']; + $values[] = $item['randomNumber']; + } else { + $update->execute([$item['randomNumber'], $item['id']]); + } } + if ($driver == 'pgsql') { + $update->execute([...$values, ...$keys]); + } return json_encode($results, JSON_NUMERIC_CHECK); } } class Connection { + private static PDO $pdo; + private static string $driver; + private static array $updates = []; private static PDOStatement $db; private static PDOStatement $fortune; private static PDOStatement $random; - private static PDOStatement $update; private static PDOStatement $query; public static function init(string $driver): void @@ -87,15 +87,16 @@ public static function init(string $driver): void "benchmarkdbpass", [ PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, - PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, - PDO::ATTR_EMULATE_PREPARES => false + PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, + PDO::ATTR_EMULATE_PREPARES => false ] ); - self::$db = self::$random = self::$query = $pdo->prepare(Operation::WORLD_SELECT_SQL); + self::$db = self::$random = self::$query = $pdo->prepare(Operation::WORLD_SELECT_SQL); self::$fortune = $pdo->prepare(Operation::FORTUNE_SQL); - self::$update = $pdo->prepare(Operation::WORLD_UPDATE_SQL); + self::$pdo = $pdo; + self::$driver = $driver; } public static function db(): string @@ -115,13 +116,23 @@ public static function query(int $queries): string public static function updates(int $queries): string { - return Operation::updates(self::$random, self::$update, $queries); + if (!isset(self::$updates[$queries])) { + self::$updates[$queries] = self::$driver == 'pgsql' + ? self::$pdo->prepare('UPDATE World SET randomNumber = CASE id'.\str_repeat(' WHEN ?::INTEGER THEN ?::INTEGER ', $queries).'END WHERE id IN ('.\str_repeat('?::INTEGER,', $queries - 1).'?::INTEGER)') + : self::$pdo->prepare(Operation::WORLD_UPDATE_SQL); + } + + return Operation::updates(self::$random, self::$updates[$queries], $queries, self::$driver); } } class Connections { private static PDOPool $pool; + private static string $driver; + private static array $dbs = []; + private static array $fortunes = []; + private static array $updates = []; public static function init(string $driver): void { @@ -133,22 +144,22 @@ public static function init(string $driver): void ->withUsername('benchmarkdbuser') ->withPassword('benchmarkdbpass'); - self::$pool = new PDOPool($config, intval(1024 / swoole_cpu_num())); + self::$pool = new PDOPool($config, 128); + self::$driver = $driver; } public static function db(): string { - $pdo = self::get(); - $result = Operation::db($pdo->prepare(Operation::WORLD_SELECT_SQL)); + $pdo = self::get(); + $result = Operation::db(self::getStatement($pdo, 'select')); self::put($pdo); - return $result; } public static function fortunes(): string { - $pdo = self::get(); - $result = Operation::fortunes($pdo->prepare(Operation::FORTUNE_SQL)); + $pdo = self::get(); + $result = Operation::fortunes(self::getStatement($pdo, 'fortunes')); self::put($pdo); return $result; @@ -156,8 +167,8 @@ public static function fortunes(): string public static function query(int $queries): string { - $pdo = self::get(); - $result = Operation::query($pdo->prepare(Operation::WORLD_SELECT_SQL), $queries); + $pdo = self::get(); + $result = Operation::query(self::getStatement($pdo, 'select'), $queries); self::put($pdo); return $result; @@ -165,8 +176,8 @@ public static function query(int $queries): string public static function updates(int $queries): string { - $pdo = self::get(); - $result = Operation::updates($pdo->prepare(Operation::WORLD_SELECT_SQL), $pdo->prepare(Operation::WORLD_UPDATE_SQL), $queries); + $pdo = self::get(); + $result = Operation::updates(self::getStatement($pdo, 'select'), self::getStatement($pdo, 'update', $queries), $queries, self::$driver); self::put($pdo); return $result; @@ -181,4 +192,31 @@ private static function put(PDO|PDOProxy $db): void { self::$pool->put($db); } + + private static function getStatement(PDO|PDOProxy $pdo, string $type, int $queries = 0): PDOStatement|PDOStatementProxy + { + $hash = spl_object_id($pdo); + + if ('select' == $type) { + if (!isset(self::$dbs[$hash])) { + self::$dbs[$hash] = $pdo->prepare(Operation::WORLD_SELECT_SQL); + } + + return self::$dbs[$hash]; + } elseif ('fortunes' == $type) { + if (!isset(self::$fortunes[$hash])) { + self::$fortunes[$hash] = $pdo->prepare(Operation::FORTUNE_SQL); + } + + return self::$fortunes[$hash]; + } else { + if (!isset(self::$updates[$hash][$queries])) { + self::$updates[$hash][$queries] = self::$driver == 'pgsql' + ? $pdo->prepare('UPDATE World SET randomNumber = CASE id'.\str_repeat(' WHEN ?::INTEGER THEN ?::INTEGER ', $queries).'END WHERE id IN ('.\str_repeat('?::INTEGER,', $queries - 1).'?::INTEGER)') + : $pdo->prepare(Operation::WORLD_UPDATE_SQL); + } + + return self::$updates[$hash][$queries]; + } + } } diff --git a/frameworks/PHP/swoole/php.ini b/frameworks/PHP/swoole/php.ini index 99a548fe57e..082e86dedbc 100644 --- a/frameworks/PHP/swoole/php.ini +++ b/frameworks/PHP/swoole/php.ini @@ -6,4 +6,4 @@ opcache.huge_code_pages=1 memory_limit=1024M opcache.jit_buffer_size=128M -opcache.jit=tracing +opcache.jit=1225 diff --git a/frameworks/PHP/swoole/swoole-async-mysql.dockerfile b/frameworks/PHP/swoole/swoole-async-mysql.dockerfile index 9b9daf07c43..82dbe32833f 100644 --- a/frameworks/PHP/swoole/swoole-async-mysql.dockerfile +++ b/frameworks/PHP/swoole/swoole-async-mysql.dockerfile @@ -1,6 +1,6 @@ -FROM ubuntu:22.04 +FROM ubuntu:24.04 -ENV SWOOLE_VERSION 5.1.1 +ENV SWOOLE_VERSION 5.1.4 ENV ENABLE_COROUTINE 1 ENV DATABASE_DRIVER mysql @@ -10,7 +10,7 @@ RUN apt update -yqq > /dev/null \ && apt install -yqq software-properties-common > /dev/null \ && LC_ALL=C.UTF-8 add-apt-repository ppa:ondrej/php > /dev/null \ && apt update -yqq > /dev/null \ - && apt install php8.3-cli php8.3-pdo-mysql php8.3-dev -y > /dev/null \ + && apt install libbrotli-dev php8.3-cli php8.3-pdo-mysql php8.3-dev -y > /dev/null \ && cd /tmp && curl -sSL "https://github.com/swoole/swoole-src/archive/v${SWOOLE_VERSION}.tar.gz" | tar xzf - \ && cd /tmp/swoole-src-${SWOOLE_VERSION} \ && phpize > /dev/null \ diff --git a/frameworks/PHP/swoole/swoole-async-postgres.dockerfile b/frameworks/PHP/swoole/swoole-async-postgres.dockerfile index d75390c922e..4a6b27b2bb0 100644 --- a/frameworks/PHP/swoole/swoole-async-postgres.dockerfile +++ b/frameworks/PHP/swoole/swoole-async-postgres.dockerfile @@ -1,6 +1,6 @@ -FROM ubuntu:22.04 +FROM ubuntu:24.04 -ENV SWOOLE_VERSION 5.1.1 +ENV SWOOLE_VERSION 5.1.4 ENV ENABLE_COROUTINE 1 ENV DATABASE_DRIVER pgsql @@ -10,7 +10,7 @@ RUN apt update -yqq > /dev/null \ && apt install -yqq software-properties-common > /dev/null \ && LC_ALL=C.UTF-8 add-apt-repository ppa:ondrej/php > /dev/null \ && apt update -yqq > /dev/null \ - && apt install php8.3-cli php8.3-pdo-pgsql php8.3-dev libpq-dev -y > /dev/null \ + && apt install libbrotli-dev php8.3-cli php8.3-pdo-pgsql php8.3-dev libpq-dev -y > /dev/null \ && cd /tmp && curl -sSL "https://github.com/swoole/swoole-src/archive/v${SWOOLE_VERSION}.tar.gz" | tar xzf - \ && cd /tmp/swoole-src-${SWOOLE_VERSION} \ && phpize > /dev/null \ diff --git a/frameworks/PHP/swoole/swoole-server.php b/frameworks/PHP/swoole/swoole-server.php index 8de85f5c0a1..3794c364cb7 100644 --- a/frameworks/PHP/swoole/swoole-server.php +++ b/frameworks/PHP/swoole/swoole-server.php @@ -48,16 +48,18 @@ $res->end($connection::fortunes()); break; case '/query': + $queries = isset($req->get['queries']) ? (int) $req->get['queries'] : -1; + $query_count = $queries > 1 ? min($queries, 500) : 1; + $res->header['Content-Type'] = 'application/json'; - $res->end($connection::query( - isset($req->get['queries']) ? (int) $req->get['queries'] : -1 - )); + $res->end($connection::query($query_count)); break; case '/updates': + $queries = isset($req->get['queries']) ? (int) $req->get['queries'] : -1; + $query_count = $queries > 1 ? min($queries, 500) : 1; + $res->header['Content-Type'] = 'application/json'; - $res->end($connection::updates( - isset($req->get['queries']) ? (int) $req->get['queries'] : -1 - )); + $res->end($connection::updates($query_count)); break; default: diff --git a/frameworks/PHP/swoole/swoole-sync-mysql.dockerfile b/frameworks/PHP/swoole/swoole-sync-mysql.dockerfile index 4893a1aad1a..97a0e11d111 100644 --- a/frameworks/PHP/swoole/swoole-sync-mysql.dockerfile +++ b/frameworks/PHP/swoole/swoole-sync-mysql.dockerfile @@ -1,6 +1,6 @@ -FROM ubuntu:22.04 +FROM ubuntu:24.04 -ENV SWOOLE_VERSION 5.1.1 +ENV SWOOLE_VERSION 5.1.4 ENV ENABLE_COROUTINE 0 ENV DATABASE_DRIVER mysql @@ -10,7 +10,7 @@ RUN apt update -yqq > /dev/null \ && apt install -yqq software-properties-common > /dev/null \ && LC_ALL=C.UTF-8 add-apt-repository ppa:ondrej/php > /dev/null \ && apt update -yqq > /dev/null \ - && apt install php8.3-cli php8.3-pdo-mysql php8.3-dev -y > /dev/null \ + && apt install libbrotli-dev php8.3-cli php8.3-pdo-mysql php8.3-dev -y > /dev/null \ && cd /tmp && curl -sSL "https://github.com/swoole/swoole-src/archive/v${SWOOLE_VERSION}.tar.gz" | tar xzf - \ && cd /tmp/swoole-src-${SWOOLE_VERSION} \ && phpize > /dev/null \ diff --git a/frameworks/PHP/swoole/swoole-sync-postgres.dockerfile b/frameworks/PHP/swoole/swoole-sync-postgres.dockerfile index 9559267ce6c..1b5a68b6169 100644 --- a/frameworks/PHP/swoole/swoole-sync-postgres.dockerfile +++ b/frameworks/PHP/swoole/swoole-sync-postgres.dockerfile @@ -1,6 +1,6 @@ -FROM ubuntu:22.04 +FROM ubuntu:24.04 -ENV SWOOLE_VERSION 5.1.1 +ENV SWOOLE_VERSION 5.1.4 ENV ENABLE_COROUTINE 0 ENV DATABASE_DRIVER pgsql @@ -10,7 +10,7 @@ RUN apt update -yqq > /dev/null \ && apt install -yqq software-properties-common > /dev/null \ && LC_ALL=C.UTF-8 add-apt-repository ppa:ondrej/php > /dev/null \ && apt update -yqq > /dev/null \ - && apt install php8.3-cli php8.3-pdo-pgsql php8.3-dev libpq-dev -y > /dev/null \ + && apt install libbrotli-dev php8.3-cli php8.3-pdo-pgsql php8.3-dev libpq-dev -y > /dev/null \ && cd /tmp && curl -sSL "https://github.com/swoole/swoole-src/archive/v${SWOOLE_VERSION}.tar.gz" | tar xzf - \ && cd /tmp/swoole-src-${SWOOLE_VERSION} \ && phpize > /dev/null \ From b356e76c8f0c3198c6111800cca88e7831e5437e Mon Sep 17 00:00:00 2001 From: Ali RajabNezhad Date: Tue, 27 Aug 2024 21:45:53 +0330 Subject: [PATCH 091/204] Update Panther Version To 4.3.1 (#9228) --- frameworks/Python/panther/README.md | 6 ++--- frameworks/Python/panther/app.py | 30 ++++++++++------------ frameworks/Python/panther/requirements.txt | 14 +++------- 3 files changed, 20 insertions(+), 30 deletions(-) diff --git a/frameworks/Python/panther/README.md b/frameworks/Python/panther/README.md index c1edfd4f5b7..f57bc888b7e 100644 --- a/frameworks/Python/panther/README.md +++ b/frameworks/Python/panther/README.md @@ -31,6 +31,6 @@ All tests are implemented in a single file ([app.py](app.py)). ## Resources -* [GitHub](https://github.com/AliRn76/Panther) -* [Documentation](https://pantherpy.github.io) -* [PyPI](https://pypi.org/project/panther) +* GitHub -> [GitHub.com/AliRn76/Panther](https://github.com/AliRn76/Panther) +* Documentation -> [PantherPy.GitHub.io](https://pantherpy.github.io) +* PyPI -> [PyPI.org/project/Panther](https://pypi.org/project/panther) diff --git a/frameworks/Python/panther/app.py b/frameworks/Python/panther/app.py index b3f712cd979..0b20d44413c 100644 --- a/frameworks/Python/panther/app.py +++ b/frameworks/Python/panther/app.py @@ -1,11 +1,12 @@ import multiprocessing -import os +from pathlib import Path from random import randint, sample import asyncpg import jinja2 from panther import Panther from panther.app import API +from panther.events import Event from panther.request import Request from panther.response import Response, PlainTextResponse, HTMLResponse @@ -18,6 +19,7 @@ pool = None +@Event.startup async def create_db_pool(): global pool pool = await asyncpg.create_pool( @@ -31,18 +33,13 @@ async def create_db_pool(): ) +@Event.shutdown async def clean_db_pool(): await pool.close() -def load_fortunes_template(): - path = os.path.join('templates', 'fortune.html') - with open(path, 'r') as template_file: - template_text = template_file.read() - return jinja2.Template(template_text) - - -fortune_template = load_fortunes_template() +with Path('templates/fortune.html').open() as f: + fortune_template = jinja2.Template(f.read()) def get_num_queries(request): @@ -99,17 +96,16 @@ async def fortunes(): @API() async def database_updates(request: Request): num_queries = get_num_queries(request) - ids = sorted(sample(range(1, 10000 + 1), num_queries)) - numbers = sorted(sample(range(1, 10000), num_queries)) - updates = list(zip(ids, numbers)) + updates = list(zip( + sample(range(1, 10000), num_queries), + sorted(sample(range(1, 10000), num_queries)) + )) - worlds = [ - {'id': row_id, 'randomNumber': number} for row_id, number in updates - ] + worlds = [{'id': row_id, 'randomNumber': number} for row_id, number in updates] async with pool.acquire() as connection: statement = await connection.prepare(READ_ROW_SQL) - for row_id, _ in updates: + for _, row_id in updates: await statement.fetchval(row_id) await connection.executemany(WRITE_ROW_SQL, updates) return Response(data=worlds) @@ -129,4 +125,4 @@ async def plaintext(): 'plaintext': plaintext, } -app = Panther(__name__, configs=__name__, urls=url_routing, startup=create_db_pool, shutdown=clean_db_pool) +app = Panther(__name__, configs=__name__, urls=url_routing) diff --git a/frameworks/Python/panther/requirements.txt b/frameworks/Python/panther/requirements.txt index 4a494ed3f7a..691d573162f 100644 --- a/frameworks/Python/panther/requirements.txt +++ b/frameworks/Python/panther/requirements.txt @@ -1,11 +1,5 @@ -panther==3.2.1 - -cython==3.0.6 -jinja2==3.1.4 - +panther==4.3.1 +cython==3.0.11 asyncpg==0.29.0 - -gunicorn==22.0.0 -uvicorn==0.24.0 -uvloop==0.19.0 -httptools==0.6.1 +gunicorn==23.0.0 +uvloop==0.20.0 From 5ec9c62c84cf5125b9fc5c9ee462b09444faa246 Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Wed, 28 Aug 2024 00:47:39 +0530 Subject: [PATCH 092/204] Upgrade Deno to v1.46 (#9230) * Upgrade Deno to v1.46 Uses the new `deno serve --parallel` feature * Fix --- frameworks/TypeScript/deno/deno.dockerfile | 4 ++-- frameworks/TypeScript/deno/src/main.ts | 13 +++---------- frameworks/TypeScript/deno/src/spawn.ts | 13 ------------- 3 files changed, 5 insertions(+), 25 deletions(-) delete mode 100644 frameworks/TypeScript/deno/src/spawn.ts diff --git a/frameworks/TypeScript/deno/deno.dockerfile b/frameworks/TypeScript/deno/deno.dockerfile index bd98d179541..cfb43644c10 100644 --- a/frameworks/TypeScript/deno/deno.dockerfile +++ b/frameworks/TypeScript/deno/deno.dockerfile @@ -1,4 +1,4 @@ -FROM denoland/deno:1.42.1 +FROM denoland/deno:1.46.1 EXPOSE 8080 @@ -12,4 +12,4 @@ RUN deno cache main.ts EXPOSE 8080 -CMD ["run", "-A", "--unstable-net", "spawn.ts"] +CMD ["deno", "serve", "--parallel", "--port", "8080", "--host", "0.0.0.0", "-A", "main.ts"] diff --git a/frameworks/TypeScript/deno/src/main.ts b/frameworks/TypeScript/deno/src/main.ts index 347e7f4c1a8..3e6f71506bd 100644 --- a/frameworks/TypeScript/deno/src/main.ts +++ b/frameworks/TypeScript/deno/src/main.ts @@ -1,9 +1,8 @@ const HELLO_WORLD_STR = "Hello, World!"; const options: ResponseInit = { headers: { "Server": "Deno" } }; -Deno.serve({ - reusePort: true, - handler: (req: Request) => { +export default { + fetch: (req: Request) => { const path = req.url.slice(req.url.indexOf("/", 8)); if (path == "/plaintext") { return new Response(HELLO_WORLD_STR, options); @@ -13,10 +12,4 @@ Deno.serve({ return new Response("404 Not Found", { status: 404, ...options }); } }, - onError(err) { - console.error(err); - Deno.exit(9); - }, - port: 8080, - hostname: "0.0.0.0", -}); +}; diff --git a/frameworks/TypeScript/deno/src/spawn.ts b/frameworks/TypeScript/deno/src/spawn.ts deleted file mode 100644 index cc56c4543b6..00000000000 --- a/frameworks/TypeScript/deno/src/spawn.ts +++ /dev/null @@ -1,13 +0,0 @@ -import os from "node:os"; -import process from "node:process"; - -const numCPUs = os.cpus().length; -for (let i = 0; i < numCPUs; i++) { - new Deno.Command(Deno.execPath(), { - args: ["run", "-A", "--unstable-net", "main.ts"], - stdin: "inherit", - stdout: "inherit", - stderr: "inherit", - env: { ...process.env }, - }).spawn(); -} From 1f84792e2083cfcbef7586de4c5466b9b2ca7131 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=A5=BF=E4=B8=9C?= Date: Wed, 28 Aug 2024 03:18:50 +0800 Subject: [PATCH 093/204] [Java] Update Solon Version To 2.9.1 (#9233) * Update Solon Version To 2.9.1 * Update Solon Version To 2.9.1 --- frameworks/Java/solon/pom.xml | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/frameworks/Java/solon/pom.xml b/frameworks/Java/solon/pom.xml index 58e7d792301..df69e436229 100644 --- a/frameworks/Java/solon/pom.xml +++ b/frameworks/Java/solon/pom.xml @@ -9,9 +9,8 @@ UTF-8 - 11 - 11 - 2.0.0 + 11 + 2.9.1 @@ -66,11 +65,11 @@ org.apache.maven.plugins maven-compiler-plugin - 3.8.1 + 3.11.0 -parameters - 1.8 - 1.8 + ${java.vertsion} + ${java.vertsion} UTF-8 false @@ -79,7 +78,7 @@ org.apache.maven.plugins maven-assembly-plugin - 3.3.0 + 3.6.0 jar-with-dependencies From 8606bb835c99db9aa9d75a5d46c52f165c58e9e1 Mon Sep 17 00:00:00 2001 From: Vladimir Shchur Date: Tue, 27 Aug 2024 22:19:13 +0300 Subject: [PATCH 094/204] [F#/Oxpecker] Improved fortunes rendering (#9234) --- frameworks/FSharp/oxpecker/src/App/App.fsproj | 5 +- frameworks/FSharp/oxpecker/src/App/Program.fs | 50 ++++++++++--------- .../FSharp/oxpecker/src/App/RenderHelpers.fs | 24 +++++++++ 3 files changed, 53 insertions(+), 26 deletions(-) create mode 100644 frameworks/FSharp/oxpecker/src/App/RenderHelpers.fs diff --git a/frameworks/FSharp/oxpecker/src/App/App.fsproj b/frameworks/FSharp/oxpecker/src/App/App.fsproj index 1b6f8b76cd3..35df8d5c493 100644 --- a/frameworks/FSharp/oxpecker/src/App/App.fsproj +++ b/frameworks/FSharp/oxpecker/src/App/App.fsproj @@ -8,12 +8,13 @@ + - - + + \ No newline at end of file diff --git a/frameworks/FSharp/oxpecker/src/App/Program.fs b/frameworks/FSharp/oxpecker/src/App/Program.fs index 09ba84b4fae..ea6bc66b911 100644 --- a/frameworks/FSharp/oxpecker/src/App/Program.fs +++ b/frameworks/FSharp/oxpecker/src/App/Program.fs @@ -7,32 +7,34 @@ open Oxpecker module HtmlViews = open Oxpecker.ViewEngine - let private fortunesHead = - head() { - title() { raw "Fortunes" } - } - - let private layout (content: HtmlElement) = - html() { - fortunesHead - body() { content } - } - - let private fortunesTableHeader = - tr() { - th() { raw "id" } - th() { raw "message" } - } + let private head, tail = + (fun (content: HtmlElement) -> + html() { + head() { + title() { "Fortunes" } + } + body() { + table() { + tr() { + th() { "id" } + th() { "message" } + } + content + } + } + } :> HtmlElement + ) |> RenderHelpers.prerender let fortunes (fortunesData: ResizeArray) = - table() { - fortunesTableHeader - for fortune in fortunesData do - tr() { - td() { raw <| string fortune.id } - td() { fortune.message } - } - } |> layout + RenderHelpers.combine head tail ( + __() { + for fortune in fortunesData do + tr() { + td() { raw <| string fortune.id } + td() { fortune.message } + } + } + ) [] module HttpHandlers = diff --git a/frameworks/FSharp/oxpecker/src/App/RenderHelpers.fs b/frameworks/FSharp/oxpecker/src/App/RenderHelpers.fs new file mode 100644 index 00000000000..003fc09d8ce --- /dev/null +++ b/frameworks/FSharp/oxpecker/src/App/RenderHelpers.fs @@ -0,0 +1,24 @@ +module RenderHelpers + + open System.Text + open Oxpecker.ViewEngine + + let prerender (view: HtmlElement -> HtmlElement) = + let sb = StringBuilder() + let mutable head = "" + let fakeHole = + { new HtmlElement with + member this.Render(sb) = + head <- sb.ToString() + sb.Clear() |> ignore } + let readyView = view fakeHole + readyView.Render(sb) + (head, sb.ToString()) + + let inline combine (head: string) (tail: string) (hole: HtmlElement) = + { new HtmlElement with + member this.Render(sb) = + sb.Append(head) |> ignore + hole.Render(sb) + sb.Append(tail) |> ignore + } \ No newline at end of file From d04efec4de37ad44cf13b453c0d2b946e2402ebd Mon Sep 17 00:00:00 2001 From: Redkale Date: Wed, 28 Aug 2024 03:19:36 +0800 Subject: [PATCH 095/204] Update jdk-23 (#9236) * Update jdk-23 * Update jdk-23 --- frameworks/Java/redkale/benchmark_config.json | 4 ++-- frameworks/Java/redkale/config.toml | 2 +- frameworks/Java/redkale/{pom-vertx.xml => pom-pgclient.xml} | 2 +- frameworks/Java/redkale/redkale-block.dockerfile | 2 +- frameworks/Java/redkale/redkale-jdbc.dockerfile | 2 +- .../{redkale-vertx.dockerfile => redkale-pgclient.dockerfile} | 4 ++-- frameworks/Java/redkale/redkale.dockerfile | 2 +- 7 files changed, 9 insertions(+), 9 deletions(-) rename frameworks/Java/redkale/{pom-vertx.xml => pom-pgclient.xml} (99%) rename frameworks/Java/redkale/{redkale-vertx.dockerfile => redkale-pgclient.dockerfile} (86%) diff --git a/frameworks/Java/redkale/benchmark_config.json b/frameworks/Java/redkale/benchmark_config.json index eb9e8d92ba2..fa84965daa3 100644 --- a/frameworks/Java/redkale/benchmark_config.json +++ b/frameworks/Java/redkale/benchmark_config.json @@ -116,7 +116,7 @@ "notes": "", "versus": "Redkale" }, - "vertx": { + "pgclient": { "db_url": "/db", "query_url": "/queries?q=", "fortune_url": "/fortunes", @@ -133,7 +133,7 @@ "webserver": "Redkale", "os": "Linux", "database_os": "Linux", - "display_name": "redkale-vertx", + "display_name": "redkale-pgclient", "notes": "", "versus": "Redkale" } diff --git a/frameworks/Java/redkale/config.toml b/frameworks/Java/redkale/config.toml index 73c0a6678e3..c2fcbb80d77 100644 --- a/frameworks/Java/redkale/config.toml +++ b/frameworks/Java/redkale/config.toml @@ -85,7 +85,7 @@ platform = "Redkale" webserver = "Redkale" versus = "Redkale" -[vertx] +[pgclient] urls.db = "/db" urls.fortune = "/fortunes" urls.query = "/queries?q=" diff --git a/frameworks/Java/redkale/pom-vertx.xml b/frameworks/Java/redkale/pom-pgclient.xml similarity index 99% rename from frameworks/Java/redkale/pom-vertx.xml rename to frameworks/Java/redkale/pom-pgclient.xml index fc371f67798..1e7315a9ff2 100644 --- a/frameworks/Java/redkale/pom-vertx.xml +++ b/frameworks/Java/redkale/pom-pgclient.xml @@ -9,7 +9,7 @@ org.redkale.boot.Application 2.9.0-SNAPSHOT 1.3.0-SNAPSHOT - 4.5.0 + 4.5.8 2.1 UTF-8 18 diff --git a/frameworks/Java/redkale/redkale-block.dockerfile b/frameworks/Java/redkale/redkale-block.dockerfile index 67594021962..36d75c9db4d 100644 --- a/frameworks/Java/redkale/redkale-block.dockerfile +++ b/frameworks/Java/redkale/redkale-block.dockerfile @@ -6,7 +6,7 @@ COPY pom.xml pom.xml COPY BenchmarkService.java src/main/java/org/redkalex/benchmark/BenchmarkService.java RUN mvn package -q -FROM openjdk:21-jdk-slim +FROM openjdk:23-jdk-slim WORKDIR /redkale COPY conf conf COPY --from=maven /redkale/target/redkale-benchmark-1.0.0.jar redkale-benchmark.jar diff --git a/frameworks/Java/redkale/redkale-jdbc.dockerfile b/frameworks/Java/redkale/redkale-jdbc.dockerfile index c6549abfa03..4588baf43f1 100644 --- a/frameworks/Java/redkale/redkale-jdbc.dockerfile +++ b/frameworks/Java/redkale/redkale-jdbc.dockerfile @@ -6,7 +6,7 @@ COPY pom-jdbc.xml pom.xml COPY BenchmarkService.java src/main/java/org/redkalex/benchmark/BenchmarkService.java RUN mvn package -q -FROM openjdk:21-jdk-slim +FROM openjdk:23-jdk-slim WORKDIR /redkale COPY conf conf COPY --from=maven /redkale/target/redkale-benchmark-1.0.0.jar redkale-benchmark.jar diff --git a/frameworks/Java/redkale/redkale-vertx.dockerfile b/frameworks/Java/redkale/redkale-pgclient.dockerfile similarity index 86% rename from frameworks/Java/redkale/redkale-vertx.dockerfile rename to frameworks/Java/redkale/redkale-pgclient.dockerfile index f4099b6a776..fdc4786a478 100644 --- a/frameworks/Java/redkale/redkale-vertx.dockerfile +++ b/frameworks/Java/redkale/redkale-pgclient.dockerfile @@ -2,10 +2,10 @@ FROM maven:3.8.6-openjdk-18-slim as maven WORKDIR /redkale COPY src src COPY conf conf -COPY pom-vertx.xml pom.xml +COPY pom-pgclient.xml pom.xml RUN mvn package -q -FROM openjdk:21-jdk-slim +FROM openjdk:23-jdk-slim WORKDIR /redkale COPY conf conf COPY --from=maven /redkale/target/redkale-benchmark-1.0.0.jar redkale-benchmark.jar diff --git a/frameworks/Java/redkale/redkale.dockerfile b/frameworks/Java/redkale/redkale.dockerfile index d7878808a4b..8982ae3b16d 100644 --- a/frameworks/Java/redkale/redkale.dockerfile +++ b/frameworks/Java/redkale/redkale.dockerfile @@ -5,7 +5,7 @@ COPY conf conf COPY pom.xml pom.xml RUN mvn package -q -FROM openjdk:21-jdk-slim +FROM openjdk:23-jdk-slim WORKDIR /redkale COPY conf conf COPY --from=maven /redkale/target/redkale-benchmark-1.0.0.jar redkale-benchmark.jar From 48de47f8d36b1fa734bb52dbde92b78760becb3a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 29 Aug 2024 18:37:57 +0000 Subject: [PATCH 096/204] Bump com.mysql:mysql-connector-j in /frameworks/Kotlin/kooby Bumps [com.mysql:mysql-connector-j](https://github.com/mysql/mysql-connector-j) from 8.0.33 to 8.2.0. - [Changelog](https://github.com/mysql/mysql-connector-j/blob/release/9.x/CHANGES) - [Commits](https://github.com/mysql/mysql-connector-j/compare/8.0.33...8.2.0) --- updated-dependencies: - dependency-name: com.mysql:mysql-connector-j dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- frameworks/Kotlin/kooby/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frameworks/Kotlin/kooby/pom.xml b/frameworks/Kotlin/kooby/pom.xml index 44397e8f522..9ae92257022 100644 --- a/frameworks/Kotlin/kooby/pom.xml +++ b/frameworks/Kotlin/kooby/pom.xml @@ -52,7 +52,7 @@ com.mysql mysql-connector-j - 8.0.33 + 8.2.0 From b8c31e25bcf99f3e20e832aa46c386ea2751fbbf Mon Sep 17 00:00:00 2001 From: Denis Stepanov Date: Fri, 30 Aug 2024 16:28:11 +0200 Subject: [PATCH 097/204] Micronaut 4.6 (#9244) * Micronaut 4.6 * Use GraalVM 21 --- frameworks/Java/micronaut/buildSrc/build.gradle | 2 +- frameworks/Java/micronaut/gradle.properties | 2 +- .../Java/micronaut/gradle/wrapper/gradle-wrapper.properties | 2 +- .../Java/micronaut/micronaut-data-jdbc-graalvm.dockerfile | 5 ++--- .../micronaut/micronaut-data-mongodb-graalvm.dockerfile | 5 ++--- .../Java/micronaut/micronaut-data-r2dbc-graalvm.dockerfile | 5 ++--- frameworks/Java/micronaut/micronaut-graalvm.dockerfile | 6 ++---- frameworks/Java/micronaut/micronaut-jdbc-graalvm.dockerfile | 5 ++--- .../Java/micronaut/micronaut-r2dbc-graalvm.dockerfile | 5 ++--- 9 files changed, 15 insertions(+), 22 deletions(-) diff --git a/frameworks/Java/micronaut/buildSrc/build.gradle b/frameworks/Java/micronaut/buildSrc/build.gradle index 7f10f90ed59..386638337fe 100644 --- a/frameworks/Java/micronaut/buildSrc/build.gradle +++ b/frameworks/Java/micronaut/buildSrc/build.gradle @@ -8,6 +8,6 @@ repositories { } dependencies { - implementation "io.micronaut.gradle:micronaut-gradle-plugin:4.3.7" + implementation "io.micronaut.gradle:micronaut-gradle-plugin:4.4.2" implementation "com.github.johnrengelman.shadow:com.github.johnrengelman.shadow.gradle.plugin:8.1.1" } \ No newline at end of file diff --git a/frameworks/Java/micronaut/gradle.properties b/frameworks/Java/micronaut/gradle.properties index ba63eab22c9..22d843f7643 100644 --- a/frameworks/Java/micronaut/gradle.properties +++ b/frameworks/Java/micronaut/gradle.properties @@ -1 +1 @@ -micronautVersion=4.5.0 +micronautVersion=4.6.0 diff --git a/frameworks/Java/micronaut/gradle/wrapper/gradle-wrapper.properties b/frameworks/Java/micronaut/gradle/wrapper/gradle-wrapper.properties index b82aa23a4f0..9355b415575 100644 --- a/frameworks/Java/micronaut/gradle/wrapper/gradle-wrapper.properties +++ b/frameworks/Java/micronaut/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.10-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/frameworks/Java/micronaut/micronaut-data-jdbc-graalvm.dockerfile b/frameworks/Java/micronaut/micronaut-data-jdbc-graalvm.dockerfile index 63eb26907b0..8d7377b166d 100644 --- a/frameworks/Java/micronaut/micronaut-data-jdbc-graalvm.dockerfile +++ b/frameworks/Java/micronaut/micronaut-data-jdbc-graalvm.dockerfile @@ -1,12 +1,11 @@ -FROM ghcr.io/graalvm/native-image-community:21-ol9 as build +FROM container-registry.oracle.com/graalvm/native-image:21 RUN microdnf install findutils # Gradle 8.7 requires xargs COPY . /home/gradle/src WORKDIR /home/gradle/src RUN ./gradlew micronaut-data-jdbc:nativeCompile -x test -x internalStartTestResourcesService --no-daemon -FROM cgr.dev/chainguard/wolfi-base:latest WORKDIR /micronaut -COPY --from=build /home/gradle/src/micronaut-data-jdbc/build/native/nativeCompile/micronaut-data-jdbc micronaut +RUN mv /home/gradle/src/micronaut-data-jdbc/build/native/nativeCompile/micronaut-data-jdbc micronaut EXPOSE 8080 ENV MICRONAUT_ENVIRONMENTS=benchmark diff --git a/frameworks/Java/micronaut/micronaut-data-mongodb-graalvm.dockerfile b/frameworks/Java/micronaut/micronaut-data-mongodb-graalvm.dockerfile index 85472860d78..f0b28e5bcf3 100644 --- a/frameworks/Java/micronaut/micronaut-data-mongodb-graalvm.dockerfile +++ b/frameworks/Java/micronaut/micronaut-data-mongodb-graalvm.dockerfile @@ -1,12 +1,11 @@ -FROM ghcr.io/graalvm/native-image-community:21-ol9 as build +FROM container-registry.oracle.com/graalvm/native-image:21 RUN microdnf install findutils # Gradle 8.7 requires xargs COPY . /home/gradle/src WORKDIR /home/gradle/src RUN ./gradlew micronaut-data-mongodb:nativeCompile -x test -x internalStartTestResourcesService --no-daemon -FROM cgr.dev/chainguard/wolfi-base:latest WORKDIR /micronaut -COPY --from=build /home/gradle/src/micronaut-data-mongodb/build/native/nativeCompile/micronaut-data-mongodb micronaut +RUN mv /home/gradle/src/micronaut-data-mongodb/build/native/nativeCompile/micronaut-data-mongodb micronaut EXPOSE 8080 ENV MICRONAUT_ENVIRONMENTS=benchmark diff --git a/frameworks/Java/micronaut/micronaut-data-r2dbc-graalvm.dockerfile b/frameworks/Java/micronaut/micronaut-data-r2dbc-graalvm.dockerfile index 6ada77518a5..614967b3379 100644 --- a/frameworks/Java/micronaut/micronaut-data-r2dbc-graalvm.dockerfile +++ b/frameworks/Java/micronaut/micronaut-data-r2dbc-graalvm.dockerfile @@ -1,12 +1,11 @@ -FROM ghcr.io/graalvm/native-image-community:21-ol9 as build +FROM container-registry.oracle.com/graalvm/native-image:21 RUN microdnf install findutils # Gradle 8.7 requires xargs COPY . /home/gradle/src WORKDIR /home/gradle/src RUN ./gradlew micronaut-data-r2dbc:nativeCompile -x test -x internalStartTestResourcesService --no-daemon -FROM cgr.dev/chainguard/wolfi-base:latest WORKDIR /micronaut -COPY --from=build /home/gradle/src/micronaut-data-r2dbc/build/native/nativeCompile/micronaut-data-r2dbc micronaut +RUN mv /home/gradle/src/micronaut-data-r2dbc/build/native/nativeCompile/micronaut-data-r2dbc micronaut EXPOSE 8080 ENV MICRONAUT_ENVIRONMENTS=benchmark diff --git a/frameworks/Java/micronaut/micronaut-graalvm.dockerfile b/frameworks/Java/micronaut/micronaut-graalvm.dockerfile index 6a9208967cc..0b45b87f1dc 100644 --- a/frameworks/Java/micronaut/micronaut-graalvm.dockerfile +++ b/frameworks/Java/micronaut/micronaut-graalvm.dockerfile @@ -1,13 +1,11 @@ -FROM ghcr.io/graalvm/native-image-community:21-ol9 as build +FROM container-registry.oracle.com/graalvm/native-image:21 RUN microdnf install findutils # Gradle 8.7 requires xargs COPY . /home/gradle/src WORKDIR /home/gradle/src RUN ./gradlew micronaut-vertx-pg-client:nativeCompile -x test -x internalStartTestResourcesService --no-daemon -FROM cgr.dev/chainguard/wolfi-base:latest -RUN apk --no-cache update && apk add libstdc++ WORKDIR /micronaut -COPY --from=build /home/gradle/src/micronaut-vertx-pg-client/build/native/nativeCompile/micronaut-vertx-pg-client micronaut +RUN mv /home/gradle/src/micronaut-vertx-pg-client/build/native/nativeCompile/micronaut-vertx-pg-client micronaut EXPOSE 8080 ENV MICRONAUT_ENVIRONMENTS=benchmark diff --git a/frameworks/Java/micronaut/micronaut-jdbc-graalvm.dockerfile b/frameworks/Java/micronaut/micronaut-jdbc-graalvm.dockerfile index 27cb088bb04..ceae0bdf03e 100644 --- a/frameworks/Java/micronaut/micronaut-jdbc-graalvm.dockerfile +++ b/frameworks/Java/micronaut/micronaut-jdbc-graalvm.dockerfile @@ -1,12 +1,11 @@ -FROM ghcr.io/graalvm/native-image-community:21-ol9 as build +FROM container-registry.oracle.com/graalvm/native-image:21 RUN microdnf install findutils # Gradle 8.7 requires xargs COPY . /home/gradle/src WORKDIR /home/gradle/src RUN ./gradlew micronaut-jdbc:nativeCompile -x test -x internalStartTestResourcesService --no-daemon -FROM cgr.dev/chainguard/wolfi-base:latest WORKDIR /micronaut -COPY --from=build /home/gradle/src/micronaut-jdbc/build/native/nativeCompile/micronaut-jdbc micronaut +RUN mv /home/gradle/src/micronaut-jdbc/build/native/nativeCompile/micronaut-jdbc micronaut EXPOSE 8080 ENV MICRONAUT_ENVIRONMENTS=benchmark diff --git a/frameworks/Java/micronaut/micronaut-r2dbc-graalvm.dockerfile b/frameworks/Java/micronaut/micronaut-r2dbc-graalvm.dockerfile index ff10709dae7..574496a0b91 100644 --- a/frameworks/Java/micronaut/micronaut-r2dbc-graalvm.dockerfile +++ b/frameworks/Java/micronaut/micronaut-r2dbc-graalvm.dockerfile @@ -1,12 +1,11 @@ -FROM ghcr.io/graalvm/native-image-community:21-ol9 as build +FROM container-registry.oracle.com/graalvm/native-image:21 RUN microdnf install findutils # Gradle 8.7 requires xargs COPY . /home/gradle/src WORKDIR /home/gradle/src RUN ./gradlew micronaut-r2dbc:nativeCompile -x test --no-daemon -FROM cgr.dev/chainguard/wolfi-base:latest WORKDIR /micronaut -COPY --from=build /home/gradle/src/micronaut-r2dbc/build/native/nativeCompile/micronaut-r2dbc micronaut +RUN mv /home/gradle/src/micronaut-r2dbc/build/native/nativeCompile/micronaut-r2dbc micronaut EXPOSE 8080 ENV MICRONAUT_ENVIRONMENTS=benchmark From 44a869e49fa0126831df30844ce4e897e4830264 Mon Sep 17 00:00:00 2001 From: Andrew James <59655451+andrew-james-dev@users.noreply.github.com> Date: Tue, 3 Sep 2024 20:47:27 +0100 Subject: [PATCH 098/204] feat: upgrade axum & dependencies, refactor, and add code and build optimisations (#9237) --- frameworks/Rust/axum/Cargo.lock | 1436 ++++++++++------- frameworks/Rust/axum/Cargo.toml | 75 +- frameworks/Rust/axum/README.md | 70 +- .../Rust/axum/axum-mongo-raw.dockerfile | 25 - frameworks/Rust/axum/axum-mongo.dockerfile | 25 - frameworks/Rust/axum/axum-pg-pool.dockerfile | 24 - frameworks/Rust/axum/axum-pg.dockerfile | 23 - frameworks/Rust/axum/axum-sqlx.dockerfile | 26 - frameworks/Rust/axum/axum.dockerfile | 27 +- frameworks/Rust/axum/benchmark_config.json | 13 + frameworks/Rust/axum/config.toml | 3 +- frameworks/Rust/axum/src/common/mod.rs | 51 + .../src/{models_mongo.rs => common/models.rs} | 5 + frameworks/Rust/axum/src/common/simd_json.rs | 152 ++ .../Rust/axum/src/{ => common}/utils.rs | 24 +- frameworks/Rust/axum/src/database_pg.rs | 199 --- frameworks/Rust/axum/src/database_sqlx.rs | 86 - frameworks/Rust/axum/src/main.rs | 42 +- frameworks/Rust/axum/src/main_mongo.rs | 76 +- frameworks/Rust/axum/src/main_mongo_raw.rs | 80 +- frameworks/Rust/axum/src/main_pg.rs | 90 +- frameworks/Rust/axum/src/main_pg_pool.rs | 136 +- frameworks/Rust/axum/src/main_sqlx.rs | 143 +- frameworks/Rust/axum/src/models_common.rs | 6 - .../{database_mongo.rs => mongo/database.rs} | 3 +- frameworks/Rust/axum/src/mongo/mod.rs | 1 + .../database.rs} | 3 +- frameworks/Rust/axum/src/mongo_raw/mod.rs | 1 + frameworks/Rust/axum/src/pg/database.rs | 155 ++ frameworks/Rust/axum/src/pg/mod.rs | 2 + .../axum/src/{models_pg.rs => pg/models.rs} | 0 .../database.rs} | 56 +- frameworks/Rust/axum/src/pg_pool/mod.rs | 2 + .../{models_pg_pool.rs => pg_pool/models.rs} | 0 frameworks/Rust/axum/src/server.rs | 119 +- frameworks/Rust/axum/src/sqlx/database.rs | 36 + frameworks/Rust/axum/src/sqlx/mod.rs | 2 + .../src/{models_sqlx.rs => sqlx/models.rs} | 0 38 files changed, 1741 insertions(+), 1476 deletions(-) delete mode 100644 frameworks/Rust/axum/axum-mongo-raw.dockerfile delete mode 100644 frameworks/Rust/axum/axum-mongo.dockerfile delete mode 100644 frameworks/Rust/axum/axum-pg-pool.dockerfile delete mode 100644 frameworks/Rust/axum/axum-pg.dockerfile delete mode 100644 frameworks/Rust/axum/axum-sqlx.dockerfile create mode 100644 frameworks/Rust/axum/src/common/mod.rs rename frameworks/Rust/axum/src/{models_mongo.rs => common/models.rs} (85%) create mode 100644 frameworks/Rust/axum/src/common/simd_json.rs rename frameworks/Rust/axum/src/{ => common}/utils.rs (65%) delete mode 100644 frameworks/Rust/axum/src/database_pg.rs delete mode 100644 frameworks/Rust/axum/src/database_sqlx.rs delete mode 100644 frameworks/Rust/axum/src/models_common.rs rename frameworks/Rust/axum/src/{database_mongo.rs => mongo/database.rs} (97%) create mode 100644 frameworks/Rust/axum/src/mongo/mod.rs rename frameworks/Rust/axum/src/{database_mongo_raw.rs => mongo_raw/database.rs} (97%) create mode 100644 frameworks/Rust/axum/src/mongo_raw/mod.rs create mode 100644 frameworks/Rust/axum/src/pg/database.rs create mode 100644 frameworks/Rust/axum/src/pg/mod.rs rename frameworks/Rust/axum/src/{models_pg.rs => pg/models.rs} (100%) rename frameworks/Rust/axum/src/{database_pg_pool.rs => pg_pool/database.rs} (60%) create mode 100644 frameworks/Rust/axum/src/pg_pool/mod.rs rename frameworks/Rust/axum/src/{models_pg_pool.rs => pg_pool/models.rs} (100%) create mode 100644 frameworks/Rust/axum/src/sqlx/database.rs create mode 100644 frameworks/Rust/axum/src/sqlx/mod.rs rename frameworks/Rust/axum/src/{models_sqlx.rs => sqlx/models.rs} (100%) diff --git a/frameworks/Rust/axum/Cargo.lock b/frameworks/Rust/axum/Cargo.lock index 3a9dba5fb18..005a10fb7ca 100644 --- a/frameworks/Rust/axum/Cargo.lock +++ b/frameworks/Rust/axum/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "addr2line" -version = "0.21.0" +version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" +checksum = "6e4503c46a5c0c7844e948c9a4d6acd9f50cccb4de1c48eb9e291ea17470c678" dependencies = [ "gimli", ] @@ -17,11 +17,17 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" +[[package]] +name = "adler2" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" + [[package]] name = "ahash" -version = "0.8.6" +version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91429305e9f0a25f6205c5b8e0d2db09e0708a7a6df0f42212bb56c32c8ac97a" +checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" dependencies = [ "cfg-if", "getrandom", @@ -32,18 +38,18 @@ dependencies = [ [[package]] name = "aho-corasick" -version = "1.1.2" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" dependencies = [ "memchr", ] [[package]] name = "allocator-api2" -version = "0.2.16" +version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0942ffc6dcaadf03badf6e6a2d0228460359d5e34b57ccdc720b7382dfbd5ec5" +checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f" [[package]] name = "android-tzdata" @@ -70,15 +76,26 @@ dependencies = [ "yansi-term", ] +[[package]] +name = "async-lock" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff6e472cdea888a4bd64f342f09b3f50e1886d32afe8df3d663c01140b811b18" +dependencies = [ + "event-listener 5.3.1", + "event-listener-strategy", + "pin-project-lite", +] + [[package]] name = "async-trait" -version = "0.1.75" +version = "0.1.81" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fdf6721fb0140e4f897002dd086c06f6c27775df19cfe1fccb21181a48fd2c98" +checksum = "6e0c28dcc82d7c8ead5cb13beb15405b57b8546e93215673ff8ca0349a028107" dependencies = [ "proc-macro2", "quote", - "syn 2.0.42", + "syn 2.0.75", ] [[package]] @@ -91,61 +108,32 @@ dependencies = [ ] [[package]] -name = "atomic-write-file" -version = "0.1.2" +name = "atomic-waker" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edcdbedc2236483ab103a53415653d6b4442ea6141baf1ffa85df29635e88436" -dependencies = [ - "nix", - "rand", -] +checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" [[package]] name = "autocfg" -version = "1.1.0" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" [[package]] name = "axum" -version = "0.2.0" -dependencies = [ - "axum 0.6.20", - "deadpool", - "deadpool-postgres", - "dotenv", - "futures", - "futures-util", - "hyper", - "mongodb", - "num_cpus", - "rand", - "serde", - "serde_json", - "sqlx", - "tokio", - "tokio-pg-mapper", - "tokio-pg-mapper-derive", - "tokio-postgres", - "tower", - "tower-http", - "yarte", -] - -[[package]] -name = "axum" -version = "0.6.20" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b829e4e32b91e643de6eafe82b1d90675f5874230191a4ffbc1b336dec4d6bf" +checksum = "3a6c9af12842a67734c9a2e355436e5d03b22383ed60cf13cd0c18fbfe3dcbcf" dependencies = [ "async-trait", "axum-core", - "bitflags 1.3.2", "bytes", "futures-util", "http", "http-body", + "http-body-util", "hyper", + "hyper-util", "itoa", "matchit", "memchr", @@ -157,41 +145,78 @@ dependencies = [ "serde_json", "serde_path_to_error", "serde_urlencoded", - "sync_wrapper", + "sync_wrapper 1.0.1", "tokio", - "tower", + "tower 0.4.13", "tower-layer", "tower-service", ] [[package]] name = "axum-core" -version = "0.3.4" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "759fa577a247914fd3f7f76d62972792636412fbfd634cd452f6a385a74d2d2c" +checksum = "a15c63fd72d41492dc4f497196f5da1fb04fb7529e631d73630d1b491e47a2e3" dependencies = [ "async-trait", "bytes", "futures-util", "http", "http-body", + "http-body-util", "mime", + "pin-project-lite", "rustversion", + "sync_wrapper 0.1.2", "tower-layer", "tower-service", ] +[[package]] +name = "axum-techempower" +version = "0.2.1" +dependencies = [ + "axum", + "axum-core", + "bytes", + "deadpool", + "deadpool-postgres", + "dotenv", + "futures", + "futures-util", + "hyper", + "hyper-util", + "mime", + "moka", + "mongodb", + "num_cpus", + "rand", + "serde", + "serde_json", + "serde_path_to_error", + "simd-json", + "socket2 0.5.7", + "sqlx", + "tokio", + "tokio-pg-mapper", + "tokio-pg-mapper-derive", + "tokio-postgres", + "tower 0.5.0", + "tower-http", + "yarte", +] + [[package]] name = "backtrace" -version = "0.3.69" +version = "0.3.73" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837" +checksum = "5cc23269a4f8976d0a4d2e7109211a419fe30e8d88d677cd60b6bc79c5732e0a" dependencies = [ "addr2line", "cc", "cfg-if", "libc", - "miniz_oxide", + "miniz_oxide 0.7.4", "object", "rustc-demangle", ] @@ -204,9 +229,15 @@ checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" [[package]] name = "base64" -version = "0.21.5" +version = "0.21.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" + +[[package]] +name = "base64" +version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35636a1494ede3b646cc98f74f8e62c773a38a659ebc777a2cf26b9b74171df9" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" [[package]] name = "base64ct" @@ -222,9 +253,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.4.1" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" +checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" dependencies = [ "serde", ] @@ -252,15 +283,15 @@ dependencies = [ [[package]] name = "bson" -version = "2.8.1" +version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88c18b51216e1f74b9d769cead6ace2f82b965b807e3d73330aabe9faec31c84" +checksum = "d8a88e82b9106923b5c4d6edfca9e7db958d4e98a478ec115022e81b9b38e2c8" dependencies = [ "ahash", "base64 0.13.1", "bitvec", "hex", - "indexmap 1.9.3", + "indexmap", "js-sys", "once_cell", "rand", @@ -273,9 +304,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.14.0" +version = "3.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec" +checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" [[package]] name = "byteorder" @@ -285,18 +316,19 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.5.0" +version = "1.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" +checksum = "8318a53db07bb3f8dca91a600466bdb3f2eaadeedfdbcf02e1accbad9271ba50" [[package]] name = "cc" -version = "1.0.83" +version = "1.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" +checksum = "72db2f7947ecee9b03b510377e8bb9077afa27176fdbff55c51027e976fdcc48" dependencies = [ "jobserver", "libc", + "shlex", ] [[package]] @@ -307,14 +339,23 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "chrono" -version = "0.4.31" +version = "0.4.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f2c685bad3eb3d45a01354cedb7d5faa66194d1d58ba6e267a8de788f79db38" +checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" dependencies = [ "android-tzdata", "iana-time-zone", "num-traits", - "windows-targets 0.48.5", + "windows-targets 0.52.6", +] + +[[package]] +name = "concurrent-queue" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" +dependencies = [ + "crossbeam-utils", ] [[package]] @@ -329,36 +370,26 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" -[[package]] -name = "core-foundation" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" -dependencies = [ - "core-foundation-sys", - "libc", -] - [[package]] name = "core-foundation-sys" -version = "0.8.6" +version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" [[package]] name = "cpufeatures" -version = "0.2.11" +version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce420fe07aecd3e67c5f910618fe65e94158f6dcc0adf44e00d69ce2bdfe0fd0" +checksum = "51e852e6dc9a5bed1fae92dd2375037bf2b768725bf3be87811edee3249d09ad" dependencies = [ "libc", ] [[package]] name = "crc" -version = "3.0.1" +version = "3.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86ec7a15cbe22e59248fc7eadb1907dab5ba09372595da4d73dd805ed4417dfe" +checksum = "69e6e4d7b33a94f0991c26729976b10ebde1d34c3ee82408fb536164fa10d636" dependencies = [ "crc-catalog", ] @@ -371,32 +402,46 @@ checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5" [[package]] name = "crc32fast" -version = "1.3.2" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" +checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" dependencies = [ "cfg-if", ] [[package]] -name = "crossbeam-queue" -version = "0.3.9" +name = "crossbeam-channel" +version = "0.5.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9bcf5bdbfdd6030fb4a1c497b5d5fc5921aa2f60d359a17e249c0e6df3de153" +checksum = "33480d6946193aa8033910124896ca395333cae7e2d1113d1fef6c3272217df2" dependencies = [ - "cfg-if", "crossbeam-utils", ] [[package]] -name = "crossbeam-utils" -version = "0.8.17" +name = "crossbeam-epoch" +version = "0.9.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c06d96137f14f244c37f989d9fff8f95e6c18b918e71f36638f8c49112e4c78f" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" dependencies = [ - "cfg-if", + "crossbeam-utils", ] +[[package]] +name = "crossbeam-queue" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df0346b5d5e76ac2fe4e327c5fd1118d6be7c51dfb18f9b7922923f287471e35" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" + [[package]] name = "crypto-common" version = "0.1.6" @@ -444,17 +489,16 @@ dependencies = [ [[package]] name = "data-encoding" -version = "2.5.0" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e962a19be5cfc3f3bf6dd8f61eb50107f356ad6270fbb3ed41476571db78be5" +checksum = "e8566979429cf69b49a5c740c60791108e86440e8be149bbea4fe54d2c32d6e2" [[package]] name = "deadpool" -version = "0.10.0" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb84100978c1c7b37f09ed3ce3e5f843af02c2a2c431bae5b19230dad2c1b490" +checksum = "6541a3916932fe57768d4be0b1ffb5ec7cbf74ca8c903fdfd5c0fe8aa958f0ed" dependencies = [ - "async-trait", "deadpool-runtime", "num_cpus", "serde", @@ -463,11 +507,14 @@ dependencies = [ [[package]] name = "deadpool-postgres" -version = "0.12.1" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bda39fa1cfff190d8924d447ad04fd22772c250438ca5ce1dfb3c80621c05aaa" +checksum = "1ab8a4ea925ce79678034870834602a2980f4b88c09e97feb266496dbb4493d2" dependencies = [ + "async-trait", "deadpool", + "getrandom", + "serde", "tokio", "tokio-postgres", "tracing", @@ -475,18 +522,18 @@ dependencies = [ [[package]] name = "deadpool-runtime" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63dfa964fe2a66f3fde91fc70b267fe193d822c7e603e2a675a49a7f46ad3f49" +checksum = "092966b41edc516079bdf31ec78a2e0588d1d0c08f78b91d8307215928642b2b" dependencies = [ "tokio", ] [[package]] name = "der" -version = "0.7.8" +version = "0.7.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fffa369a668c8af7dbf8b5e56c9f744fbd399949ed171606040001947de40b1c" +checksum = "f55bf8e7b65898637379c1b74eb1551107c8294ed26d855ceb9fd1a09cfc9bc0" dependencies = [ "const-oid", "pem-rfc7468", @@ -495,9 +542,9 @@ dependencies = [ [[package]] name = "deranged" -version = "0.3.10" +version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8eb30d70a07a3b04884d2677f06bec33509dc67ca60d92949e5535352d3191dc" +checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" dependencies = [ "powerfmt", ] @@ -515,15 +562,15 @@ dependencies = [ [[package]] name = "derive_more" -version = "0.99.17" +version = "0.99.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321" +checksum = "5f33878137e4dafd7fa914ad4e259e18a4e8e532b9617a2d0150262bf53abfce" dependencies = [ "convert_case", "proc-macro2", "quote", "rustc_version 0.4.0", - "syn 1.0.109", + "syn 2.0.75", ] [[package]] @@ -558,9 +605,9 @@ checksum = "dcbb2bf8e87535c23f7a8a321e364ce21462d0ff10cb6407820e8e96dfff6653" [[package]] name = "either" -version = "1.9.0" +version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" +checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" dependencies = [ "serde", ] @@ -585,9 +632,9 @@ checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] name = "errno" -version = "0.3.8" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" +checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" dependencies = [ "libc", "windows-sys 0.52.0", @@ -610,6 +657,27 @@ version = "2.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" +[[package]] +name = "event-listener" +version = "5.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6032be9bd27023a771701cc49f9f053c751055f71efb2e0ae5c15809093675ba" +dependencies = [ + "concurrent-queue", + "parking", + "pin-project-lite", +] + +[[package]] +name = "event-listener-strategy" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f214dc438f977e6d4e3500aaa277f5ad94ca83fbbd9b1a15713ce2344ccc5a1" +dependencies = [ + "event-listener 5.3.1", + "pin-project-lite", +] + [[package]] name = "fallible-iterator" version = "0.2.0" @@ -618,24 +686,27 @@ checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7" [[package]] name = "fastrand" -version = "2.0.1" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" +checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a" [[package]] -name = "finl_unicode" -version = "1.2.0" +name = "flate2" +version = "1.0.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fcfdc7a0362c9f4444381a9e697c79d435fe65b52a37466fc2c1184cee9edc6" +checksum = "9c0596c1eac1f9e04ed902702e9878208b336edc9d6fddc8a48387349bab3666" +dependencies = [ + "crc32fast", + "miniz_oxide 0.8.0", +] [[package]] -name = "flate2" -version = "1.0.28" +name = "float-cmp" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46303f565772937ffe1d394a4fac6f411c6013172fadde9dcdb1e147a086940e" +checksum = "98de4bbd547a563b716d8dfa9aad1cb19bfab00f4fa09a6a4ed21dbcf44ce9c4" dependencies = [ - "crc32fast", - "miniz_oxide", + "num-traits", ] [[package]] @@ -646,7 +717,7 @@ checksum = "55ac459de2512911e4b674ce33cf20befaba382d05b62b008afc1c8b57cbf181" dependencies = [ "futures-core", "futures-sink", - "spin 0.9.8", + "spin", ] [[package]] @@ -655,21 +726,6 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" -[[package]] -name = "foreign-types" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" -dependencies = [ - "foreign-types-shared", -] - -[[package]] -name = "foreign-types-shared" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" - [[package]] name = "form_urlencoded" version = "1.2.1" @@ -687,9 +743,9 @@ checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" [[package]] name = "futures" -version = "0.3.29" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da0290714b38af9b4a7b094b8a37086d1b4e61f2df9122c3cad2577669145335" +checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0" dependencies = [ "futures-channel", "futures-core", @@ -702,9 +758,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.29" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff4dd66668b557604244583e3e1e1eada8c5c2e96a6d0d6653ede395b78bbacb" +checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" dependencies = [ "futures-core", "futures-sink", @@ -712,15 +768,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.29" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb1d22c66e66d9d72e1758f0bd7d4fd0bee04cad842ee34587d68c07e45d088c" +checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" [[package]] name = "futures-executor" -version = "0.3.29" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f4fb8693db0cf099eadcca0efe2a5a22e4550f98ed16aba6c48700da29597bc" +checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d" dependencies = [ "futures-core", "futures-task", @@ -740,38 +796,38 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.29" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8bf34a163b5c4c52d0478a4d757da8fb65cabef42ba90515efee0f6f9fa45aaa" +checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" [[package]] name = "futures-macro" -version = "0.3.29" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53b153fd91e4b0147f4aced87be237c98248656bb01050b96bf3ee89220a8ddb" +checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ "proc-macro2", "quote", - "syn 2.0.42", + "syn 2.0.75", ] [[package]] name = "futures-sink" -version = "0.3.29" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e36d3378ee38c2a36ad710c5d30c2911d752cb941c00c72dbabfb786a7970817" +checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" [[package]] name = "futures-task" -version = "0.3.29" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "efd193069b0ddadc69c46389b740bbccdd97203899b48d09c5f7969591d6bae2" +checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" [[package]] name = "futures-util" -version = "0.3.29" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a19526d624e703a3179b3d322efec918b6246ea0fa51d41124525f00f1cc8104" +checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" dependencies = [ "futures-channel", "futures-core", @@ -797,32 +853,57 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.11" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe9006bed769170c11f845cf00c7c1e9092aeb3f268e007c3e760ac68008070f" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" dependencies = [ "cfg-if", + "js-sys", "libc", "wasi", + "wasm-bindgen", ] [[package]] name = "gimli" -version = "0.28.1" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" +checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd" [[package]] -name = "hashbrown" -version = "0.12.3" +name = "h2" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" +checksum = "524e8ac6999421f49a846c2d4411f337e53497d8ec55d67753beffa43c5d9205" +dependencies = [ + "atomic-waker", + "bytes", + "fnv", + "futures-core", + "futures-sink", + "http", + "indexmap", + "slab", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "halfbrown" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8588661a8607108a5ca69cab034063441a0413a0b041c13618a7dd348021ef6f" +dependencies = [ + "hashbrown", + "serde", +] [[package]] name = "hashbrown" -version = "0.14.3" +version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" dependencies = [ "ahash", "allocator-api2", @@ -834,7 +915,7 @@ version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e8094feaf31ff591f651a2664fb9cfd92bba7a60ce3197265e9482ebe753c8f7" dependencies = [ - "hashbrown 0.14.3", + "hashbrown", ] [[package]] @@ -848,9 +929,9 @@ dependencies = [ [[package]] name = "hermit-abi" -version = "0.3.3" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d77f7ec81a6d05a3abb01ab6eb7590f6083d08449fe5a1c8b1e620283546ccb7" +checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" [[package]] name = "hex" @@ -898,9 +979,9 @@ dependencies = [ [[package]] name = "http" -version = "0.2.11" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8947b1a6fad4393052c7ba1f4cd97bed3e953a95c79c92ad9b051a04611d9fbb" +checksum = "21b9ddb458710bc376481b842f5da65cdf31522de232c1ca8146abce2a358258" dependencies = [ "bytes", "fnv", @@ -909,26 +990,32 @@ dependencies = [ [[package]] name = "http-body" -version = "0.4.6" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" +checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" dependencies = [ "bytes", "http", - "pin-project-lite", ] [[package]] -name = "http-range-header" -version = "0.3.1" +name = "http-body-util" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "add0ab9360ddbd88cfeb3bd9574a1d85cfdfa14db10b3e21d3700dbc4328758f" +checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f" +dependencies = [ + "bytes", + "futures-util", + "http", + "http-body", + "pin-project-lite", +] [[package]] name = "httparse" -version = "1.8.0" +version = "1.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" +checksum = "0fcc0b4a115bf80b728eb8ea024ad5bd707b615bfed49e0665b6e0f86fd082d9" [[package]] name = "httpdate" @@ -938,32 +1025,44 @@ checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" [[package]] name = "hyper" -version = "0.14.28" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf96e135eb83a2a8ddf766e426a841d8ddd7449d5f00d34ea02b41d2f19eef80" +checksum = "50dfd22e0e76d0f662d429a5f80fcaf3855009297eab6a0a9f8543834744ba05" dependencies = [ "bytes", "futures-channel", - "futures-core", "futures-util", + "h2", "http", "http-body", "httparse", "httpdate", "itoa", "pin-project-lite", - "socket2 0.5.5", + "smallvec", + "tokio", +] + +[[package]] +name = "hyper-util" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cde7055719c54e36e95e8719f95883f22072a48ede39db7fc17a4e1d5281e9b9" +dependencies = [ + "bytes", + "futures-util", + "http", + "http-body", + "hyper", + "pin-project-lite", "tokio", - "tower-service", - "tracing", - "want", ] [[package]] name = "iana-time-zone" -version = "0.1.58" +version = "0.1.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8326b86b6cff230b97d0d312a6c40a60726df3332e721f72a1b035f451663b20" +checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141" dependencies = [ "android_system_properties", "core-foundation-sys", @@ -1011,22 +1110,12 @@ dependencies = [ [[package]] name = "indexmap" -version = "1.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" -dependencies = [ - "autocfg", - "hashbrown 0.12.3", -] - -[[package]] -name = "indexmap" -version = "2.1.0" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f" +checksum = "93ead53efc7ea8ed3cfb0c79fc8023fbb782a5432b52830b6518941cebe6505c" dependencies = [ "equivalent", - "hashbrown 0.14.3", + "hashbrown", ] [[package]] @@ -1035,7 +1124,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b58db92f96b720de98181bbbe63c831e87005ab460c1bf306eb2622b4707997f" dependencies = [ - "socket2 0.5.5", + "socket2 0.5.7", "widestring", "windows-sys 0.48.0", "winreg", @@ -1047,53 +1136,108 @@ version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" -[[package]] -name = "itertools" -version = "0.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25db6b064527c5d482d0423354fcd07a89a2dfe07b67892e62411946db7f07b0" -dependencies = [ - "either", -] - [[package]] name = "itoa" -version = "1.0.10" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" +checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" [[package]] name = "jobserver" -version = "0.1.27" +version = "0.1.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c37f63953c4c63420ed5fd3d6d398c719489b9f872b9fa683262f8edd363c7d" +checksum = "48d1dbcbbeb6a7fec7e059840aa538bd62aaccf972c7346c4d9d2059312853d0" dependencies = [ "libc", ] [[package]] name = "js-sys" -version = "0.3.66" +version = "0.3.70" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cee9c64da59eae3b50095c18d3e74f8b73c0b86d2792824ff01bbce68ba229ca" +checksum = "1868808506b929d7b0cfa8f75951347aa71bb21144b7791bae35d9bccfcfe37a" dependencies = [ "wasm-bindgen", ] [[package]] name = "lazy_static" -version = "1.4.0" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" +dependencies = [ + "spin", +] + +[[package]] +name = "lexical-core" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2cde5de06e8d4c2faabc400238f9ae1c74d5412d03a7bd067645ccbc47070e46" +dependencies = [ + "lexical-parse-float", + "lexical-parse-integer", + "lexical-util", + "lexical-write-float", + "lexical-write-integer", +] + +[[package]] +name = "lexical-parse-float" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +checksum = "683b3a5ebd0130b8fb52ba0bdc718cc56815b6a097e28ae5a6997d0ad17dc05f" dependencies = [ - "spin 0.5.2", + "lexical-parse-integer", + "lexical-util", + "static_assertions", +] + +[[package]] +name = "lexical-parse-integer" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d0994485ed0c312f6d965766754ea177d07f9c00c9b82a5ee62ed5b47945ee9" +dependencies = [ + "lexical-util", + "static_assertions", +] + +[[package]] +name = "lexical-util" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5255b9ff16ff898710eb9eb63cb39248ea8a5bb036bea8085b1a767ff6c4e3fc" +dependencies = [ + "static_assertions", +] + +[[package]] +name = "lexical-write-float" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accabaa1c4581f05a3923d1b4cfd124c329352288b7b9da09e766b0668116862" +dependencies = [ + "lexical-util", + "lexical-write-integer", + "static_assertions", +] + +[[package]] +name = "lexical-write-integer" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1b6f3d1f4422866b68192d62f77bc5c700bee84f3069f2469d7bc8c77852446" +dependencies = [ + "lexical-util", + "static_assertions", ] [[package]] name = "libc" -version = "0.2.151" +version = "0.2.158" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "302d7ab3130588088d277783b1e2d2e10c9e9e4a16dd9050e6ec93fb3e7048f4" +checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439" [[package]] name = "libm" @@ -1120,15 +1264,15 @@ checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" [[package]] name = "linux-raw-sys" -version = "0.4.12" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4cd1a83af159aa67994778be9070f0ae1bd732942279cabb14f86f986a21456" +checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" [[package]] name = "lock_api" -version = "0.4.11" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45" +checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" dependencies = [ "autocfg", "scopeguard", @@ -1136,9 +1280,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.20" +version = "0.4.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" +checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" [[package]] name = "lru-cache" @@ -1179,9 +1323,9 @@ dependencies = [ [[package]] name = "memchr" -version = "2.6.4" +version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "mime" @@ -1197,29 +1341,63 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] name = "miniz_oxide" -version = "0.7.1" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" +checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08" dependencies = [ "adler", ] +[[package]] +name = "miniz_oxide" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2d80299ef12ff69b16a84bb182e3b9df68b5a91574d3d4fa6e41b65deec4df1" +dependencies = [ + "adler2", +] + [[package]] name = "mio" -version = "0.8.10" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f3d0b296e374a4e6f3c7b0a1f5a51d748a0d34c85e7dc48fc3fa9a87657fe09" +checksum = "80e04d1dcff3aae0704555fe5fee3bcfaf3d1fdf8a7e521d5b9d2b42acb52cec" dependencies = [ + "hermit-abi", "libc", "wasi", - "windows-sys 0.48.0", + "windows-sys 0.52.0", +] + +[[package]] +name = "moka" +version = "0.12.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32cf62eb4dd975d2dde76432fb1075c49e3ee2331cf36f1f8fd4b66550d32b6f" +dependencies = [ + "async-lock", + "async-trait", + "crossbeam-channel", + "crossbeam-epoch", + "crossbeam-utils", + "event-listener 5.3.1", + "futures-util", + "once_cell", + "parking_lot", + "quanta", + "rustc_version 0.4.0", + "smallvec", + "tagptr", + "thiserror", + "triomphe", + "uuid", ] [[package]] name = "mongodb" -version = "2.8.0" +version = "2.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46c30763a5c6c52079602be44fa360ca3bfacee55fca73f4734aecd23706a7f2" +checksum = "ef206acb1b72389b49bc9985efe7eb1f8a9bb18e5680d262fac26c07f44025f1" dependencies = [ "async-trait", "base64 0.13.1", @@ -1249,49 +1427,20 @@ dependencies = [ "sha-1", "sha2", "snap", - "socket2 0.4.10", - "stringprep", - "strsim", - "take_mut", - "thiserror", - "tokio", - "tokio-rustls", - "tokio-util", - "trust-dns-proto", - "trust-dns-resolver", - "typed-builder", - "uuid", - "webpki-roots", - "zstd", -] - -[[package]] -name = "native-tls" -version = "0.2.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07226173c32f2926027b63cce4bcd8076c3552846cbe7925f3aaffeac0a3b92e" -dependencies = [ - "lazy_static", - "libc", - "log", - "openssl", - "openssl-probe", - "openssl-sys", - "schannel", - "security-framework", - "security-framework-sys", - "tempfile", -] - -[[package]] -name = "nix" -version = "0.27.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2eb04e9c688eff1c89d72b407f168cf79bb9e867a9d3323ed6c01519eb9cc053" -dependencies = [ - "bitflags 2.4.1", - "cfg-if", - "libc", + "socket2 0.4.10", + "stringprep", + "strsim", + "take_mut", + "thiserror", + "tokio", + "tokio-rustls", + "tokio-util", + "trust-dns-proto", + "trust-dns-resolver", + "typed-builder", + "uuid", + "webpki-roots", + "zstd", ] [[package]] @@ -1321,21 +1470,26 @@ dependencies = [ "zeroize", ] +[[package]] +name = "num-conv" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" + [[package]] name = "num-integer" -version = "0.1.45" +version = "0.1.46" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" dependencies = [ - "autocfg", "num-traits", ] [[package]] name = "num-iter" -version = "0.1.43" +version = "0.1.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d03e6c028c5dc5cac6e2dec0efda81fc887605bb3d884578bb6d6bf7514e252" +checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" dependencies = [ "autocfg", "num-integer", @@ -1344,9 +1498,9 @@ dependencies = [ [[package]] name = "num-traits" -version = "0.2.17" +version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ "autocfg", "libm", @@ -1364,9 +1518,9 @@ dependencies = [ [[package]] name = "object" -version = "0.32.1" +version = "0.36.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cf5f9dd3933bd50a9e1f149ec995f39ae2c496d31fd772c1fd45ebc27e902b0" +checksum = "27b64972346851a39438c60b341ebc01bba47464ae329e55cf343eb93964efd9" dependencies = [ "memchr", ] @@ -1378,54 +1532,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" [[package]] -name = "openssl" -version = "0.10.66" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9529f4786b70a3e8c61e11179af17ab6188ad8d0ded78c5529441ed39d4bd9c1" -dependencies = [ - "bitflags 2.4.1", - "cfg-if", - "foreign-types", - "libc", - "once_cell", - "openssl-macros", - "openssl-sys", -] - -[[package]] -name = "openssl-macros" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.42", -] - -[[package]] -name = "openssl-probe" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" - -[[package]] -name = "openssl-sys" -version = "0.9.103" +name = "parking" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f9e8deee91df40a943c71b917e5874b951d32a802526c85721ce3b776c929d6" -dependencies = [ - "cc", - "libc", - "pkg-config", - "vcpkg", -] +checksum = "bb813b8af86854136c6922af0598d719255ecb2179515e6e7730d468f05c9cae" [[package]] name = "parking_lot" -version = "0.12.1" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" +checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" dependencies = [ "lock_api", "parking_lot_core", @@ -1433,22 +1549,22 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.9" +version = "0.9.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e" +checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" dependencies = [ "cfg-if", "libc", - "redox_syscall", + "redox_syscall 0.5.3", "smallvec", - "windows-targets 0.48.5", + "windows-targets 0.52.6", ] [[package]] name = "paste" -version = "1.0.14" +version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" [[package]] name = "pbkdf2" @@ -1494,29 +1610,29 @@ dependencies = [ [[package]] name = "pin-project" -version = "1.1.3" +version = "1.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fda4ed1c6c173e3fc7a83629421152e01d7b1f9b7f65fb301e490e8cfc656422" +checksum = "b6bf43b791c5b9e34c3d182969b4abb522f9343702850a2e57f460d00d09b4b3" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" -version = "1.1.3" +version = "1.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405" +checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" dependencies = [ "proc-macro2", "quote", - "syn 2.0.42", + "syn 2.0.75", ] [[package]] name = "pin-project-lite" -version = "0.2.13" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" +checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" [[package]] name = "pin-utils" @@ -1547,17 +1663,17 @@ dependencies = [ [[package]] name = "pkg-config" -version = "0.3.28" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69d3587f8a9e599cc7ec2c00e331f71c4e69a5f9a4b8a6efd5b07466b9736f9a" +checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" [[package]] name = "postgres-protocol" -version = "0.6.6" +version = "0.6.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49b6c5ef183cd3ab4ba005f1ca64c21e8bd97ce4699cfea9e8d9a2c4958ca520" +checksum = "acda0ebdebc28befa84bee35e651e4c5f09073d668c7aed4cf7e23c3cda84b23" dependencies = [ - "base64 0.21.5", + "base64 0.22.1", "byteorder", "bytes", "fallible-iterator", @@ -1571,9 +1687,9 @@ dependencies = [ [[package]] name = "postgres-types" -version = "0.2.6" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d2234cdee9408b523530a9b6d2d6b373d1db34f6a8e51dc03ded1828d7fb67c" +checksum = "02048d9e032fb3cc3413bbf7b83a15d84a5d419778e2628751896d856498eee9" dependencies = [ "bytes", "fallible-iterator", @@ -1588,9 +1704,12 @@ checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" [[package]] name = "ppv-lite86" -version = "0.2.17" +version = "0.2.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" +checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" +dependencies = [ + "zerocopy", +] [[package]] name = "prettyplease" @@ -1604,13 +1723,28 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.70" +version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39278fbbf5fb4f646ce651690877f89d1c5811a3d4acb27700c1cb3cdb78fd3b" +checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" dependencies = [ "unicode-ident", ] +[[package]] +name = "quanta" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e5167a477619228a0b284fac2674e3c388cba90631d7b7de620e6f1fcd08da5" +dependencies = [ + "crossbeam-utils", + "libc", + "once_cell", + "raw-cpuid", + "wasi", + "web-sys", + "winapi", +] + [[package]] name = "quick-error" version = "1.2.3" @@ -1619,9 +1753,9 @@ checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" [[package]] name = "quote" -version = "1.0.33" +version = "1.0.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" +checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" dependencies = [ "proc-macro2", ] @@ -1662,6 +1796,15 @@ dependencies = [ "getrandom", ] +[[package]] +name = "raw-cpuid" +version = "11.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb9ee317cfe3fbd54b36a511efc1edd42e216903c9cd575e686dd68a2ba90d8d" +dependencies = [ + "bitflags 2.6.0", +] + [[package]] name = "redox_syscall" version = "0.4.1" @@ -1671,11 +1814,40 @@ dependencies = [ "bitflags 1.3.2", ] +[[package]] +name = "redox_syscall" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a908a6e00f1fdd0dfd9c0eb08ce85126f6d8bbda50017e74bc4a4b7d4a926a4" +dependencies = [ + "bitflags 2.6.0", +] + +[[package]] +name = "ref-cast" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccf0a6f84d5f1d581da8b41b47ec8600871962f2a528115b542b362d4b744931" +dependencies = [ + "ref-cast-impl", +] + +[[package]] +name = "ref-cast-impl" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bcc303e793d3734489387d205e9b186fac9c6cfacedd98cbb2e8a5943595f3e6" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.75", +] + [[package]] name = "regex" -version = "1.10.2" +version = "1.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343" +checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619" dependencies = [ "aho-corasick", "memchr", @@ -1685,9 +1857,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.3" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f" +checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" dependencies = [ "aho-corasick", "memchr", @@ -1696,9 +1868,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.8.2" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" +checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" [[package]] name = "resolv-conf" @@ -1712,16 +1884,17 @@ dependencies = [ [[package]] name = "ring" -version = "0.17.7" +version = "0.17.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "688c63d65483050968b2a8937f7995f443e27041a0f7700aa59b0822aedebb74" +checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" dependencies = [ "cc", + "cfg-if", "getrandom", "libc", - "spin 0.9.8", + "spin", "untrusted", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] @@ -1746,9 +1919,9 @@ dependencies = [ [[package]] name = "rustc-demangle" -version = "0.1.23" +version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" +checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" [[package]] name = "rustc_version" @@ -1765,7 +1938,7 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" dependencies = [ - "semver 1.0.20", + "semver 1.0.23", ] [[package]] @@ -1780,11 +1953,11 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.28" +version = "0.38.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72e572a5e8ca657d7366229cdde4bd14c4eb5499a9573d4d366fe1b599daa316" +checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" dependencies = [ - "bitflags 2.4.1", + "bitflags 2.6.0", "errno", "libc", "linux-raw-sys", @@ -1793,9 +1966,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.21.11" +version = "0.21.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fecbfb7b1444f477b345853b1fce097a2c6fb637b2bfb87e6bc5db0f043fae4" +checksum = "3f56a14d1f48b391359b22f731fd4bd7e43c97f3c50eee276f3aa09c94784d3e" dependencies = [ "log", "ring", @@ -1809,7 +1982,7 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" dependencies = [ - "base64 0.21.5", + "base64 0.21.7", ] [[package]] @@ -1824,24 +1997,15 @@ dependencies = [ [[package]] name = "rustversion" -version = "1.0.14" +version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4" +checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6" [[package]] name = "ryu" -version = "1.0.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f98d2aa92eebf49b69786be48e4477826b256916e84a57ff2a4f21923b48eb4c" - -[[package]] -name = "schannel" -version = "0.1.22" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c3733bf4cf7ea0880754e19cb5a462007c4a8c1914bff372ccc95b464f1df88" -dependencies = [ - "windows-sys 0.48.0", -] +checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" [[package]] name = "scopeguard" @@ -1859,29 +2023,6 @@ dependencies = [ "untrusted", ] -[[package]] -name = "security-framework" -version = "2.9.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05b64fb303737d99b81884b2c63433e9ae28abebe5eb5045dcdd175dc2ecf4de" -dependencies = [ - "bitflags 1.3.2", - "core-foundation", - "core-foundation-sys", - "libc", - "security-framework-sys", -] - -[[package]] -name = "security-framework-sys" -version = "2.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e932934257d3b408ed8f30db49d85ea163bfe74961f017f405b025af298f0c7a" -dependencies = [ - "core-foundation-sys", - "libc", -] - [[package]] name = "semver" version = "0.9.0" @@ -1893,9 +2034,9 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.20" +version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "836fa6a3e1e547f9a2c4040802ec865b5d85f4014efe00555d7090a3dcaa1090" +checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" [[package]] name = "semver-parser" @@ -1905,50 +2046,51 @@ checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" [[package]] name = "serde" -version = "1.0.193" +version = "1.0.208" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25dd9975e68d0cb5aa1120c288333fc98731bd1dd12f561e468ea4728c042b89" +checksum = "cff085d2cb684faa248efb494c39b68e522822ac0de72ccf08109abde717cfb2" dependencies = [ "serde_derive", ] [[package]] name = "serde_bytes" -version = "0.11.12" +version = "0.11.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab33ec92f677585af6d88c65593ae2375adde54efdbf16d597f2cbc7a6d368ff" +checksum = "387cc504cb06bb40a96c8e04e951fe01854cf6bc921053c954e4a606d9675c6a" dependencies = [ "serde", ] [[package]] name = "serde_derive" -version = "1.0.193" +version = "1.0.208" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3" +checksum = "24008e81ff7613ed8e5ba0cfaf24e2c2f1e5b8a0495711e44fcd4882fca62bcf" dependencies = [ "proc-macro2", "quote", - "syn 2.0.42", + "syn 2.0.75", ] [[package]] name = "serde_json" -version = "1.0.108" +version = "1.0.127" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d1c7e3eac408d115102c4c24ad393e0821bb3a5df4d506a80f85f7a742a526b" +checksum = "8043c06d9f82bd7271361ed64f415fe5e12a77fdb52e573e7f06a516dea329ad" dependencies = [ - "indexmap 2.1.0", + "indexmap", "itoa", + "memchr", "ryu", "serde", ] [[package]] name = "serde_path_to_error" -version = "0.1.14" +version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4beec8bce849d58d06238cb50db2e1c417cfeafa4c63f692b15c82b7c80f8335" +checksum = "af99884400da37c88f5e9146b7f1fd0fbcae8f6eec4e9da38b67d05486f814a6" dependencies = [ "itoa", "serde", @@ -2021,11 +2163,17 @@ dependencies = [ "digest", ] +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + [[package]] name = "signal-hook-registry" -version = "1.4.1" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1" +checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1" dependencies = [ "libc", ] @@ -2040,6 +2188,28 @@ dependencies = [ "rand_core", ] +[[package]] +name = "simd-json" +version = "0.13.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "570c430b3d902ea083097e853263ae782dfe40857d93db019a12356c8e8143fa" +dependencies = [ + "getrandom", + "halfbrown", + "lexical-core", + "ref-cast", + "serde", + "serde_json", + "simdutf8", + "value-trait", +] + +[[package]] +name = "simdutf8" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f27f6278552951f1f2b8cf9da965d10969b2efdea95a6ec47987ab46edfe263a" + [[package]] name = "siphasher" version = "0.3.11" @@ -2057,9 +2227,9 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.11.2" +version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4dccd0940a2dcdf68d092b8cbab7dc0ad8fa938bf95787e1b916b0e3d0e8e970" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" [[package]] name = "snap" @@ -2079,20 +2249,14 @@ dependencies = [ [[package]] name = "socket2" -version = "0.5.5" +version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b5fac59a5cb5dd637972e5fca70daf0523c9067fcdc4842f053dae04a18f8e9" +checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c" dependencies = [ "libc", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] -[[package]] -name = "spin" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" - [[package]] name = "spin" version = "0.9.8" @@ -2114,20 +2278,19 @@ dependencies = [ [[package]] name = "sqlformat" -version = "0.2.3" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce81b7bd7c4493975347ef60d8c7e8b742d4694f4c49f93e0a12ea263938176c" +checksum = "f895e3734318cc55f1fe66258926c9b910c124d47520339efecbb6c59cec7c1f" dependencies = [ - "itertools", "nom", "unicode_categories", ] [[package]] name = "sqlx" -version = "0.7.3" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dba03c279da73694ef99763320dea58b51095dfe87d001b1d4b5fe78ba8763cf" +checksum = "c9a2ccff1a000a5a59cd33da541d9f2fdcd9e6e8229cc200565942bff36d0aaa" dependencies = [ "sqlx-core", "sqlx-macros", @@ -2138,9 +2301,9 @@ dependencies = [ [[package]] name = "sqlx-core" -version = "0.7.3" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d84b0a3c3739e220d94b3239fd69fb1f74bc36e16643423bd99de3b43c21bfbd" +checksum = "24ba59a9342a3d9bab6c56c118be528b27c9b60e490080e9711a04dccac83ef6" dependencies = [ "ahash", "atoi", @@ -2148,9 +2311,8 @@ dependencies = [ "bytes", "crc", "crossbeam-queue", - "dotenvy", "either", - "event-listener", + "event-listener 2.5.3", "futures-channel", "futures-core", "futures-intrusive", @@ -2158,13 +2320,14 @@ dependencies = [ "futures-util", "hashlink", "hex", - "indexmap 2.1.0", + "indexmap", "log", "memchr", - "native-tls", "once_cell", "paste", "percent-encoding", + "rustls", + "rustls-pemfile", "serde", "serde_json", "sha2", @@ -2175,13 +2338,14 @@ dependencies = [ "tokio-stream", "tracing", "url", + "webpki-roots", ] [[package]] name = "sqlx-macros" -version = "0.7.3" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89961c00dc4d7dffb7aee214964b065072bff69e36ddb9e2c107541f75e4f2a5" +checksum = "4ea40e2345eb2faa9e1e5e326db8c34711317d2b5e08d0d5741619048a803127" dependencies = [ "proc-macro2", "quote", @@ -2192,11 +2356,10 @@ dependencies = [ [[package]] name = "sqlx-macros-core" -version = "0.7.3" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0bd4519486723648186a08785143599760f7cc81c52334a55d6a83ea1e20841" +checksum = "5833ef53aaa16d860e92123292f1f6a3d53c34ba8b1969f152ef1a7bb803f3c8" dependencies = [ - "atomic-write-file", "dotenvy", "either", "heck", @@ -2219,13 +2382,13 @@ dependencies = [ [[package]] name = "sqlx-mysql" -version = "0.7.3" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e37195395df71fd068f6e2082247891bc11e3289624bbc776a0cdfa1ca7f1ea4" +checksum = "1ed31390216d20e538e447a7a9b959e06ed9fc51c37b514b46eb758016ecd418" dependencies = [ "atoi", - "base64 0.21.5", - "bitflags 2.4.1", + "base64 0.21.7", + "bitflags 2.6.0", "byteorder", "bytes", "crc", @@ -2261,13 +2424,13 @@ dependencies = [ [[package]] name = "sqlx-postgres" -version = "0.7.3" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6ac0ac3b7ccd10cc96c7ab29791a7dd236bd94021f31eec7ba3d46a74aa1c24" +checksum = "7c824eb80b894f926f89a0b9da0c7f435d27cdd35b8c655b114e58223918577e" dependencies = [ "atoi", - "base64 0.21.5", - "bitflags 2.4.1", + "base64 0.21.7", + "bitflags 2.6.0", "byteorder", "crc", "dotenvy", @@ -2288,7 +2451,6 @@ dependencies = [ "rand", "serde", "serde_json", - "sha1", "sha2", "smallvec", "sqlx-core", @@ -2300,9 +2462,9 @@ dependencies = [ [[package]] name = "sqlx-sqlite" -version = "0.7.3" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "210976b7d948c7ba9fced8ca835b11cbb2d677c59c79de41ac0d397e14547490" +checksum = "b244ef0a8414da0bed4bb1910426e890b19e5e9bccc27ada6b797d05c55ae0aa" dependencies = [ "atoi", "flume", @@ -2321,15 +2483,21 @@ dependencies = [ "urlencoding", ] +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + [[package]] name = "stringprep" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb41d74e231a107a1b4ee36bd1214b11285b77768d2e3824aedafa988fd36ee6" +checksum = "7b4df3d392d81bd458a8a621b8bffbd2302a12ffe288a9d931670948749463b1" dependencies = [ - "finl_unicode", "unicode-bidi", "unicode-normalization", + "unicode-properties", ] [[package]] @@ -2340,9 +2508,9 @@ checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" [[package]] name = "subtle" -version = "2.5.0" +version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "syn" @@ -2357,9 +2525,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.42" +version = "2.0.75" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b7d0a2c048d661a1a59fcd7355baa232f7ed34e0ee4df2eef3c1c1c0d3852d8" +checksum = "f6af063034fc1935ede7be0122941bafa9bacb949334d090b77ca98b5817c7d9" dependencies = [ "proc-macro2", "quote", @@ -2372,6 +2540,18 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" +[[package]] +name = "sync_wrapper" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7065abeca94b6a8a577f9bd45aa0867a2238b74e8eb67cf10d492bc39351394" + +[[package]] +name = "tagptr" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b2093cf4c8eb1e67749a6762251bc9cd836b6fc171623bd0a9d324d37af2417" + [[package]] name = "take_mut" version = "0.2.2" @@ -2386,45 +2566,46 @@ checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" [[package]] name = "tempfile" -version = "3.8.1" +version = "3.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ef1adac450ad7f4b3c28589471ade84f25f731a7a0fe30d71dfa9f60fd808e5" +checksum = "04cbcdd0c794ebb0d4cf35e88edd2f7d2c4c3e9a5a6dab322839b321c6a87a64" dependencies = [ "cfg-if", "fastrand", - "redox_syscall", + "once_cell", "rustix", - "windows-sys 0.48.0", + "windows-sys 0.59.0", ] [[package]] name = "thiserror" -version = "1.0.51" +version = "1.0.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f11c217e1416d6f036b870f14e0413d480dbf28edbee1f877abaf0206af43bb7" +checksum = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.51" +version = "1.0.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01742297787513b79cf8e29d1056ede1313e2420b7b3b15d0a768b4921f549df" +checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261" dependencies = [ "proc-macro2", "quote", - "syn 2.0.42", + "syn 2.0.75", ] [[package]] name = "time" -version = "0.3.31" +version = "0.3.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f657ba42c3f86e7680e53c8cd3af8abbe56b5491790b46e22e19c0d57463583e" +checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885" dependencies = [ "deranged", "itoa", + "num-conv", "powerfmt", "serde", "time-core", @@ -2439,18 +2620,19 @@ checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" [[package]] name = "time-macros" -version = "0.2.16" +version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26197e33420244aeb70c3e8c78376ca46571bc4e701e4791c2cd9f57dcb3a43f" +checksum = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf" dependencies = [ + "num-conv", "time-core", ] [[package]] name = "tinyvec" -version = "1.6.0" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +checksum = "445e881f4f6d382d5f27c034e25eb92edd7c784ceab92a0937db7f2e9471b938" dependencies = [ "tinyvec_macros", ] @@ -2463,32 +2645,31 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.35.1" +version = "1.39.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c89b4efa943be685f629b149f53829423f8f5531ea21249408e8e2f8671ec104" +checksum = "9babc99b9923bfa4804bd74722ff02c0381021eafa4db9949217e3be8e84fff5" dependencies = [ "backtrace", "bytes", "libc", "mio", - "num_cpus", "parking_lot", "pin-project-lite", "signal-hook-registry", - "socket2 0.5.5", + "socket2 0.5.7", "tokio-macros", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] name = "tokio-macros" -version = "2.2.0" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" +checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" dependencies = [ "proc-macro2", "quote", - "syn 2.0.42", + "syn 2.0.75", ] [[package]] @@ -2513,9 +2694,9 @@ dependencies = [ [[package]] name = "tokio-postgres" -version = "0.7.10" +version = "0.7.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d340244b32d920260ae7448cb72b6e238bddc3d4f7603394e7dd46ed8e48f5b8" +checksum = "03adcf0147e203b6032c0b2d30be1415ba03bc348901f3ff1cc0df6a733e60c3" dependencies = [ "async-trait", "byteorder", @@ -2531,7 +2712,7 @@ dependencies = [ "postgres-protocol", "postgres-types", "rand", - "socket2 0.5.5", + "socket2 0.5.7", "tokio", "tokio-util", "whoami", @@ -2549,9 +2730,9 @@ dependencies = [ [[package]] name = "tokio-stream" -version = "0.1.14" +version = "0.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "397c988d37662c7dda6d2208364a706264bf3d6138b11d436cbac0ad38832842" +checksum = "267ac89e0bec6e691e5813911606935d77c476ff49024f98abcea3e7b15e37af" dependencies = [ "futures-core", "pin-project-lite", @@ -2560,9 +2741,9 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.10" +version = "0.7.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5419f34732d9eb6ee4c3578b7989078579b7f039cbbb9ca2c4da015749371e15" +checksum = "9cf6b47b3771c49ac75ad09a6162f53ad4b8088b76ac60e8ec1455b31a189fe1" dependencies = [ "bytes", "futures-core", @@ -2570,7 +2751,6 @@ dependencies = [ "futures-sink", "pin-project-lite", "tokio", - "tracing", ] [[package]] @@ -2595,22 +2775,33 @@ dependencies = [ "tokio", "tower-layer", "tower-service", - "tracing", ] [[package]] -name = "tower-http" -version = "0.4.4" +name = "tower" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61c5bb1d698276a2443e5ecfabc1008bf15a36c12e6a7176e7bf089ea9131140" +checksum = "36b837f86b25d7c0d7988f00a54e74739be6477f2aac6201b8f429a7569991b7" dependencies = [ - "bitflags 2.4.1", - "bytes", "futures-core", "futures-util", + "pin-project-lite", + "sync_wrapper 0.1.2", + "tower-layer", + "tower-service", +] + +[[package]] +name = "tower-http" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e9cd434a998747dd2c4276bc96ee2e0c7a2eadf3cae88e52be55a05fa9053f5" +dependencies = [ + "bitflags 2.6.0", + "bytes", "http", "http-body", - "http-range-header", + "http-body-util", "pin-project-lite", "tower-layer", "tower-service", @@ -2618,15 +2809,15 @@ dependencies = [ [[package]] name = "tower-layer" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c20c8dbed6283a09604c3e69b4b7eeb54e298b8a600d4d5ecb5ad39de609f1d0" +checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" [[package]] name = "tower-service" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" +checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" [[package]] name = "tracing" @@ -2648,7 +2839,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.42", + "syn 2.0.75", ] [[package]] @@ -2660,6 +2851,12 @@ dependencies = [ "once_cell", ] +[[package]] +name = "triomphe" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "859eb650cfee7434994602c3a68b25d77ad9e68c8a6cd491616ef86661382eb3" + [[package]] name = "trust-dns-proto" version = "0.21.2" @@ -2705,12 +2902,6 @@ dependencies = [ "trust-dns-proto", ] -[[package]] -name = "try-lock" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" - [[package]] name = "typed-builder" version = "0.10.0" @@ -2730,9 +2921,9 @@ checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" [[package]] name = "unicode-bidi" -version = "0.3.14" +version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f2528f27a9eb2b21e69c95319b30bd0efd85d09c379741b0f78ea1d86be2416" +checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" [[package]] name = "unicode-ident" @@ -2742,30 +2933,36 @@ checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" [[package]] name = "unicode-normalization" -version = "0.1.22" +version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" +checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5" dependencies = [ "tinyvec", ] +[[package]] +name = "unicode-properties" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52ea75f83c0137a9b98608359a5f1af8144876eb67bcb1ce837368e906a9f524" + [[package]] name = "unicode-segmentation" -version = "1.10.1" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36" +checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202" [[package]] name = "unicode-width" -version = "0.1.11" +version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85" +checksum = "0336d538f7abc86d282a4189614dfaa90810dfc2c6f6427eaf88e16311dd225d" [[package]] name = "unicode-xid" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" +checksum = "229730647fbc343e3a80e463c1db7f78f3855d3f3739bee0dda773c9a037c90a" [[package]] name = "unicode_categories" @@ -2781,9 +2978,9 @@ checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" [[package]] name = "url" -version = "2.5.0" +version = "2.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633" +checksum = "22784dbdf76fdde8af1aeda5622b546b422b6fc585325248a2bf9f5e41e94d6c" dependencies = [ "form_urlencoded", "idna 0.5.0", @@ -2798,9 +2995,9 @@ checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da" [[package]] name = "uuid" -version = "1.6.1" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e395fcf16a7a3d8127ec99782007af141946b4795001f876d54fb0d55978560" +checksum = "81dfa00651efa65069b0b6b651f4aaa31ba9e3c3ce0137aaad053604ee7e0314" dependencies = [ "getrandom", "serde", @@ -2822,6 +3019,18 @@ version = "0.15.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4e8257fbc510f0a46eb602c10215901938b5c2a7d5e70fc11483b1d3c9b5b18c" +[[package]] +name = "value-trait" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dad8db98c1e677797df21ba03fca7d3bf9bec3ca38db930954e4fe6e1ea27eb4" +dependencies = [ + "float-cmp", + "halfbrown", + "itoa", + "ryu", +] + [[package]] name = "vcpkg" version = "0.2.15" @@ -2830,18 +3039,9 @@ checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" [[package]] name = "version_check" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" - -[[package]] -name = "want" -version = "0.3.1" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" -dependencies = [ - "try-lock", -] +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" [[package]] name = "wasi" @@ -2857,34 +3057,35 @@ checksum = "b8dad83b4f25e74f184f64c43b150b91efe7647395b42289f38e50566d82855b" [[package]] name = "wasm-bindgen" -version = "0.2.89" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ed0d4f68a3015cc185aff4db9506a015f4b96f95303897bfa23f846db54064e" +checksum = "a82edfc16a6c469f5f44dc7b571814045d60404b55a0ee849f9bcfa2e63dd9b5" dependencies = [ "cfg-if", + "once_cell", "wasm-bindgen-macro", ] [[package]] name = "wasm-bindgen-backend" -version = "0.2.89" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b56f625e64f3a1084ded111c4d5f477df9f8c92df113852fa5a374dbda78826" +checksum = "9de396da306523044d3302746f1208fa71d7532227f15e347e2d93e4145dd77b" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", - "syn 2.0.42", + "syn 2.0.75", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-macro" -version = "0.2.89" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0162dbf37223cd2afce98f3d0785506dcb8d266223983e4b5b525859e6e182b2" +checksum = "585c4c91a46b072c92e908d99cb1dcdf95c5218eeb6f3bf1efa991ee7a68cccf" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -2892,28 +3093,28 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.89" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0eb82fcb7930ae6219a7ecfd55b217f5f0893484b7a13022ebb2b2bf20b5283" +checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836" dependencies = [ "proc-macro2", "quote", - "syn 2.0.42", + "syn 2.0.75", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.89" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ab9b36309365056cd639da3134bf87fa8f3d86008abf99e612384a6eecd459f" +checksum = "c62a0a307cb4a311d3a07867860911ca130c3494e8c2719593806c08bc5d0484" [[package]] name = "web-sys" -version = "0.3.66" +version = "0.3.70" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50c24a44ec86bb68fbecd1b3efed7e85ea5621b39b35ef2766b66cd984f8010f" +checksum = "26fdeaafd9bd129f65e7c031593c24d62186301e0c72c8978fa1678be7d532c0" dependencies = [ "js-sys", "wasm-bindgen", @@ -2921,9 +3122,9 @@ dependencies = [ [[package]] name = "webpki-roots" -version = "0.25.3" +version = "0.25.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1778a42e8b3b90bff8d0f5032bf22250792889a5cdc752aa0020c84abe3aaf10" +checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1" [[package]] name = "whoami" @@ -2931,16 +3132,16 @@ version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a44ab49fad634e88f55bf8f9bb3abd2f27d7204172a112c7c9987e01c1c94ea9" dependencies = [ - "redox_syscall", + "redox_syscall 0.4.1", "wasite", "web-sys", ] [[package]] name = "widestring" -version = "1.0.2" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "653f141f39ec16bba3c5abe400a0c60da7468261cc2cbf36805022876bc721a8" +checksum = "7219d36b6eac893fa81e84ebe06485e7dcbb616177469b142df14f1f4deb1311" [[package]] name = "winapi" @@ -2966,11 +3167,11 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "windows-core" -version = "0.51.1" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1f8cf84f35d2db49a46868f947758c7a1138116f7fac3bc844f43ade1292e64" +checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" dependencies = [ - "windows-targets 0.48.5", + "windows-targets 0.52.6", ] [[package]] @@ -2988,7 +3189,16 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets 0.52.0", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets 0.52.6", ] [[package]] @@ -3008,17 +3218,18 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.52.0" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ - "windows_aarch64_gnullvm 0.52.0", - "windows_aarch64_msvc 0.52.0", - "windows_i686_gnu 0.52.0", - "windows_i686_msvc 0.52.0", - "windows_x86_64_gnu 0.52.0", - "windows_x86_64_gnullvm 0.52.0", - "windows_x86_64_msvc 0.52.0", + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", + "windows_i686_gnullvm", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", ] [[package]] @@ -3029,9 +3240,9 @@ checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" [[package]] name = "windows_aarch64_gnullvm" -version = "0.52.0" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" [[package]] name = "windows_aarch64_msvc" @@ -3041,9 +3252,9 @@ checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" [[package]] name = "windows_aarch64_msvc" -version = "0.52.0" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" [[package]] name = "windows_i686_gnu" @@ -3053,9 +3264,15 @@ checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" [[package]] name = "windows_i686_gnu" -version = "0.52.0" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" [[package]] name = "windows_i686_msvc" @@ -3065,9 +3282,9 @@ checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" [[package]] name = "windows_i686_msvc" -version = "0.52.0" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" [[package]] name = "windows_x86_64_gnu" @@ -3077,9 +3294,9 @@ checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" [[package]] name = "windows_x86_64_gnu" -version = "0.52.0" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" [[package]] name = "windows_x86_64_gnullvm" @@ -3089,9 +3306,9 @@ checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" [[package]] name = "windows_x86_64_gnullvm" -version = "0.52.0" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" [[package]] name = "windows_x86_64_msvc" @@ -3101,9 +3318,9 @@ checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] name = "windows_x86_64_msvc" -version = "0.52.0" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "winreg" @@ -3220,29 +3437,30 @@ dependencies = [ [[package]] name = "zerocopy" -version = "0.7.31" +version = "0.7.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c4061bedbb353041c12f413700357bec76df2c7e2ca8e4df8bac24c6bf68e3d" +checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" dependencies = [ + "byteorder", "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.7.31" +version = "0.7.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3c129550b3e6de3fd0ba67ba5c81818f9805e58b8d7fee80a3a59d2c9fc601a" +checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.42", + "syn 2.0.75", ] [[package]] name = "zeroize" -version = "1.7.0" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d" +checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" [[package]] name = "zstd" @@ -3265,9 +3483,9 @@ dependencies = [ [[package]] name = "zstd-sys" -version = "2.0.9+zstd.1.5.5" +version = "2.0.13+zstd.1.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e16efa8a874a0481a574084d34cc26fdb3b99627480f785888deb6386506656" +checksum = "38ff0f21cfee8f97d94cef41359e0c89aa6113028ab0291aa8ca0038995a95aa" dependencies = [ "cc", "pkg-config", diff --git a/frameworks/Rust/axum/Cargo.toml b/frameworks/Rust/axum/Cargo.toml index f4ecf45adf4..49b594972d1 100644 --- a/frameworks/Rust/axum/Cargo.toml +++ b/frameworks/Rust/axum/Cargo.toml @@ -1,6 +1,6 @@ [package] -name = "axum" -version = "0.2.0" +name = "axum-techempower" +version = "0.2.1" authors = ["Dragos Varovici "] edition = "2021" @@ -28,28 +28,63 @@ path = "src/main_mongo_raw.rs" name = "axum-pg" path = "src/main_pg.rs" +[features] +default = [] +simd-json = [ + "dep:simd-json", + "dep:axum-core", + "dep:mime", + "dep:bytes", + "dep:serde_path_to_error", +] + [dependencies] -axum = { version = "0.6.16", default-features = false, features = ["json", "query", "http1", "tokio"] } -deadpool = { version = "0.10.0", features = ["rt_tokio_1", "serde", "async-trait", "managed" ] } -deadpool-postgres = "0.12.1" +axum = { version = "0.7.5", default-features = false, features = [ + "json", + "query", + "http1", + "tokio", +] } +deadpool = { version = "0.12.1", features = ["rt_tokio_1", "serde", "managed"] } +deadpool-postgres = { version = "0.14.0", features = ["rt_tokio_1", "serde"] } dotenv = "0.15.0" -futures = "0.3.25" -futures-util = "0.3.25" -hyper = { version = "0.14.23", features = ["http1", "server"] } -mongodb = { version = "2.3.1", features = ["zstd-compression", "snappy-compression", "zlib-compression"] } -num_cpus = "1.14.0" +futures = "0.3.30" +futures-util = "0.3.30" +mongodb = { version = "2.8.0", features = [ + "zstd-compression", + "snappy-compression", + "zlib-compression", +] } +num_cpus = "1.16.0" rand = { version = "0.8.5", features = ["small_rng"] } -serde = { version = "1.0.149", features = ["derive"] } -serde_json = "1.0.89" -sqlx = { version = "0.7.3", features = ["postgres", "macros", "runtime-tokio-native-tls"] } -tokio = { version = "1.24.2", features = ["full"] } -tokio-pg-mapper = "0.2.0" -tokio-pg-mapper-derive = "0.2.0" -tokio-postgres = "0.7.7" -tower = { version = "0.4.13", features = ["util"] } -tower-http = { version = "0.4.0", features = ["set-header"] } +serde = { version = "1.0.196", features = ["derive"] } +serde_json = "1.0.127" +sqlx = { version = "0.7.3", features = [ + "postgres", + "macros", + "runtime-tokio", + "tls-rustls", +] } +tokio = { version = "1.39.3", features = ["full"] } +tokio-pg-mapper = { version = "0.2.0" } +tokio-pg-mapper-derive = { version = "0.2.0" } +tokio-postgres = { version = "0.7.11" } +tower = { version = "0.5.0", features = ["util"] } +tower-http = { version = "0.5.2", features = ["set-header"] } yarte = "0.15.7" +simd-json = { version = "0.13.8", optional = true } +axum-core = { version = "0.4.3", optional = true } +mime = { version = "0.3.17", optional = true } +bytes = { version = "1.5.0", optional = true } +serde_path_to_error = { version = "0.1.15", optional = true } +moka = { version = "0.12.8", features = ["future"] } +socket2 = "0.5.7" +hyper = { version = "1.4", features = ["server", "http1"] } +hyper-util = { version = "0.1", features = ["tokio", "server-auto", "http1"] } + [profile.release] -lto = true +lto = "fat" codegen-units = 1 +strip = true +opt-level = 3 diff --git a/frameworks/Rust/axum/README.md b/frameworks/Rust/axum/README.md index 55ca3e0978e..59979fe441d 100755 --- a/frameworks/Rust/axum/README.md +++ b/frameworks/Rust/axum/README.md @@ -1,42 +1,46 @@ - -# [Axum](https://github.com/tokio-rs/axum) - Ergonomic and modular web framework built with Tokio, Tower, and Hyper +# [Axum](https://github.com/tokio-rs/axum) ## Description -Axum is a web application framework that focuses on ergonomics and modularity. - -* [User Guide](https://docs.rs/axum/0.3/axum/) -* [API Documentation](https://docs.rs/axum/0.3/axum/) -* Cargo package: [axum](https://crates.io/crates/axum) +Axum is a web application framework that focuses on ergonomics and modularity, +built with Tokio, Tower, and Hyper. -## Database +- [User Guide](https://docs.rs/axum/latest/axum/) +- [API Documentation](https://docs.rs/axum/latest/axum/) +- [Cargo Package (`axum`)](https://crates.io/crates/axum) -PostgreSQL +## Variants -* Raw using [sqlx](https://github.com/launchbadge/sqlx) +- PostgreSQL using `SQLx`, `tokio_postgres`, and `deadpool`. +- MongoDB with `mongodb`. ## Test URLs -### Test 1: JSON Encoding - - http://localhost:8000/json - -### Test 2: Single Row Query - - http://localhost:8000/db - -### Test 3: Multi Row Query - - http://localhost:8000/queries?q=20 - -### Test 4: Fortunes (Template rendering) - - http://localhost:8000/fortunes - -### Test 5: Update Query - - http://localhost:8000/updates?q=20 - -### Test 6: Plaintext - - http://localhost:8000/plaintext +- Plaintext: http://localhost:8000/plaintext +- JSON Encoding: http://localhost:8000/json +- Single Row Query: http://localhost:8000/db +- Multi Row Query: http://localhost:8000/queries?q=20 +- Fortunes: http://localhost:8000/fortunes +- Update Query: http://localhost:8000/updates?q=20 +- Cached Query: http://localhost:8000/cached-queries?q=20 + +## Notable Points (both performance and build) + +- Use of `async`. +- Use of most recent versions of Rust, `axum` and dependencies. +- (Disabled by default) Compile-time swap-in of `simd-json` instead of `serde_json` for faster JSON serialization. +- Release binaries are stripped and compiled with CPU native. +- Sockets configured with TCP_NODELAY and to support an increased number of pending connections. +- Server configured to serve HTTP/1 only, with no need for websockets. +- Separation of build and deployment containers using multi-stage builds. +- Deployment into Google's minimal `distroless-cc` container. +- Use of pipelined database queries (where supported). +- Streaming database queries (where supported). +- Use of PostgreSQL prepared statements cache (where supported). +- Use of PostgreSQL arrays to execute multi-row database updates with a single `UPDATE` query. + - This is permitted by the [test requirements](https://github.com/TechEmpower/FrameworkBenchmarks/wiki/Project-Information-Framework-Tests-Overview#database-updates), step (ix). +- In version 0.7.6 (as yet unreleased), a native API to set TCP_NODELAY will be included. + - https://github.com/tokio-rs/axum/pull/2653/ + - https://github.com/tokio-rs/axum/issues/2521 +- More performance improvements are to be expected in version 0.8: + - https://github.com/tokio-rs/axum/issues/1827 diff --git a/frameworks/Rust/axum/axum-mongo-raw.dockerfile b/frameworks/Rust/axum/axum-mongo-raw.dockerfile deleted file mode 100644 index ffdabfc2d8c..00000000000 --- a/frameworks/Rust/axum/axum-mongo-raw.dockerfile +++ /dev/null @@ -1,25 +0,0 @@ -FROM rust:1.75-slim-buster - -ENV AXUM_TECHEMPOWER_MONGODB_URL=mongodb://tfb-database:27017 -ENV AXUM_TECHEMPOWER_MAX_POOL_SIZE=28 -ENV AXUM_TECHEMPOWER_MIN_POOL_SIZE=14 - -RUN apt-get update && apt-get install -y --no-install-recommends \ - pkg-config libssl-dev \ - && rm -rf /var/lib/apt/lists/* - -WORKDIR /axum -COPY ./src ./src -COPY ./templates ./templates -COPY ./Cargo.toml ./Cargo.toml -COPY ./Cargo.lock ./Cargo.lock -COPY ./run.sh ./run.sh -RUN chmod +x ./run.sh - -ENV RUSTFLAGS "-C target-cpu=native" -RUN cargo build --release -RUN cp ./target/release/axum-mongo-raw ./target/release/axum-techempower - -EXPOSE 8000 - -CMD ["./run.sh"] diff --git a/frameworks/Rust/axum/axum-mongo.dockerfile b/frameworks/Rust/axum/axum-mongo.dockerfile deleted file mode 100644 index 99a6f76f997..00000000000 --- a/frameworks/Rust/axum/axum-mongo.dockerfile +++ /dev/null @@ -1,25 +0,0 @@ -FROM rust:1.75-slim-buster - -ENV AXUM_TECHEMPOWER_MONGODB_URL=mongodb://tfb-database:27017 -ENV AXUM_TECHEMPOWER_MAX_POOL_SIZE=28 -ENV AXUM_TECHEMPOWER_MIN_POOL_SIZE=14 - -RUN apt-get update && apt-get install -y --no-install-recommends \ - pkg-config libssl-dev \ - && rm -rf /var/lib/apt/lists/* - -WORKDIR /axum -COPY ./src ./src -COPY ./templates ./templates -COPY ./Cargo.toml ./Cargo.toml -COPY ./Cargo.lock ./Cargo.lock -COPY ./run.sh ./run.sh -RUN chmod +x ./run.sh - -ENV RUSTFLAGS "-C target-cpu=native" -RUN cargo build --release -RUN cp ./target/release/axum-mongo ./target/release/axum-techempower - -EXPOSE 8000 - -CMD ["./run.sh"] diff --git a/frameworks/Rust/axum/axum-pg-pool.dockerfile b/frameworks/Rust/axum/axum-pg-pool.dockerfile deleted file mode 100644 index c836faa2381..00000000000 --- a/frameworks/Rust/axum/axum-pg-pool.dockerfile +++ /dev/null @@ -1,24 +0,0 @@ -FROM rust:1.75-slim-buster - -ENV AXUM_TECHEMPOWER_DATABASE_URL=postgres://benchmarkdbuser:benchmarkdbpass@tfb-database/hello_world -ENV AXUM_TECHEMPOWER_MAX_POOL_SIZE=28 - -RUN apt-get update && apt-get install -y --no-install-recommends \ - libpq-dev pkg-config libssl-dev \ - && rm -rf /var/lib/apt/lists/* - -WORKDIR /axum -COPY ./src ./src -COPY ./templates ./templates -COPY ./Cargo.toml ./Cargo.toml -COPY ./Cargo.lock ./Cargo.lock -COPY ./run.sh ./run.sh -RUN chmod +x ./run.sh - -ENV RUSTFLAGS "-C target-cpu=native" -RUN cargo build --release -RUN cp ./target/release/axum-pg-pool ./target/release/axum-techempower - -EXPOSE 8000 - -CMD ["./run.sh"] diff --git a/frameworks/Rust/axum/axum-pg.dockerfile b/frameworks/Rust/axum/axum-pg.dockerfile deleted file mode 100644 index 98d44481007..00000000000 --- a/frameworks/Rust/axum/axum-pg.dockerfile +++ /dev/null @@ -1,23 +0,0 @@ -FROM rust:1.75-slim-buster - -ENV AXUM_TECHEMPOWER_DATABASE_URL=postgres://benchmarkdbuser:benchmarkdbpass@tfb-database/hello_world - -RUN apt-get update && apt-get install -y --no-install-recommends \ - libpq-dev pkg-config libssl-dev \ - && rm -rf /var/lib/apt/lists/* - -WORKDIR /axum -COPY ./src ./src -COPY ./templates ./templates -COPY ./Cargo.toml ./Cargo.toml -COPY ./Cargo.lock ./Cargo.lock -COPY ./run.sh ./run.sh -RUN chmod +x ./run.sh - -ENV RUSTFLAGS "-C target-cpu=native" -RUN cargo build --release -RUN cp ./target/release/axum-pg ./target/release/axum-techempower - -EXPOSE 8000 - -CMD ["./run.sh"] diff --git a/frameworks/Rust/axum/axum-sqlx.dockerfile b/frameworks/Rust/axum/axum-sqlx.dockerfile deleted file mode 100644 index 0cecda65f32..00000000000 --- a/frameworks/Rust/axum/axum-sqlx.dockerfile +++ /dev/null @@ -1,26 +0,0 @@ -FROM rust:1.75-slim-buster - -ENV AXUM_TECHEMPOWER_DATABASE_URL=postgres://benchmarkdbuser:benchmarkdbpass@tfb-database/hello_world -ENV AXUM_TECHEMPOWER_MAX_POOL_SIZE=56 -ENV AXUM_TECHEMPOWER_MIN_POOL_SIZE=56 - -RUN apt-get update && apt-get install -y --no-install-recommends \ - libpq-dev pkg-config libssl-dev \ - && rm -rf /var/lib/apt/lists/* - -WORKDIR /axum -COPY ./src ./src -COPY ./templates ./templates -COPY ./Cargo.toml ./Cargo.toml -COPY ./Cargo.lock ./Cargo.lock -COPY ./run.sh ./run.sh -RUN chmod +x ./run.sh - -ENV RUSTFLAGS "-C target-cpu=native" -RUN cargo build --release -RUN cp ./target/release/axum-sqlx ./target/release/axum-techempower - - -EXPOSE 8000 - -CMD ["./run.sh"] diff --git a/frameworks/Rust/axum/axum.dockerfile b/frameworks/Rust/axum/axum.dockerfile index 2cd772a3426..044e68bbf02 100644 --- a/frameworks/Rust/axum/axum.dockerfile +++ b/frameworks/Rust/axum/axum.dockerfile @@ -1,21 +1,24 @@ -FROM rust:1.75-slim-buster +FROM docker.io/rust:1.80-slim-bookworm AS builder RUN apt-get update && apt-get install -y --no-install-recommends \ pkg-config libssl-dev \ && rm -rf /var/lib/apt/lists/* -WORKDIR /axum -COPY ./src ./src -COPY ./templates ./templates -COPY ./Cargo.toml ./Cargo.toml -COPY ./Cargo.lock ./Cargo.lock -COPY ./run.sh ./run.sh -RUN chmod +x ./run.sh - +WORKDIR /build +COPY ./Cargo.toml ./Cargo.lock /build/ +RUN cargo fetch +COPY ./templates/ /build/templates +COPY ./src/ /build/src ENV RUSTFLAGS "-C target-cpu=native" RUN cargo build --release -RUN cp ./target/release/axum ./target/release/axum-techempower +FROM gcr.io/distroless/cc-debian12 +ENV POSTGRES_URL=postgres://benchmarkdbuser:benchmarkdbpass@tfb-database/hello_world +ENV POSTGRES_MIN_POOL_SIZE=56 +ENV POSTGRES_MAX_POOL_SIZE=56 +ENV MONGODB_URL=mongodb://tfb-database:27017 +ENV MONGODB_MIN_POOL_SIZE=28 +ENV MONGODB_MAX_POOL_SIZE=14 +COPY --from=builder /build/target/release/axum* /app/ EXPOSE 8000 - -CMD ["./run.sh"] +CMD ["/app/axum"] diff --git a/frameworks/Rust/axum/benchmark_config.json b/frameworks/Rust/axum/benchmark_config.json index f05dd4a67dd..ade60875389 100755 --- a/frameworks/Rust/axum/benchmark_config.json +++ b/frameworks/Rust/axum/benchmark_config.json @@ -3,6 +3,8 @@ "tests": [ { "default": { + "dockerfile": "axum.dockerfile", + "docker_cmd": "/app/axum", "json_url": "/json", "plaintext_url": "/plaintext", "port": 8000, @@ -22,8 +24,11 @@ "versus": "None" }, "sqlx": { + "dockerfile": "axum.dockerfile", + "docker_cmd": "/app/axum-sqlx", "db_url": "/db", "fortune_url": "/fortunes", + "cached_query_url": "/cached-queries?queries=", "port": 8000, "approach": "Realistic", "classification": "Fullstack", @@ -41,6 +46,8 @@ "versus": "None" }, "pg": { + "dockerfile": "axum.dockerfile", + "docker_cmd": "/app/axum-pg", "db_url": "/db", "fortune_url": "/fortunes", "query_url": "/queries?queries=", @@ -62,6 +69,8 @@ "versus": "None" }, "pg-pool": { + "dockerfile": "axum.dockerfile", + "docker_cmd": "/app/axum-pg-pool", "db_url": "/db", "query_url": "/queries?queries=", "update_url": "/updates?queries=", @@ -83,6 +92,8 @@ "versus": "None" }, "mongo": { + "dockerfile": "axum.dockerfile", + "docker_cmd": "/app/axum-mongo", "db_url": "/db", "query_url": "/queries?queries=", "fortune_url": "/fortunes", @@ -104,6 +115,8 @@ "versus": "None" }, "mongo-raw": { + "dockerfile": "axum.dockerfile", + "docker_cmd": "/app/axum-mongo-raw", "db_url": "/db", "query_url": "/queries?queries=", "update_url": "/updates?queries=", diff --git a/frameworks/Rust/axum/config.toml b/frameworks/Rust/axum/config.toml index d4bb9d7ad0e..b5695c19bf0 100644 --- a/frameworks/Rust/axum/config.toml +++ b/frameworks/Rust/axum/config.toml @@ -8,6 +8,7 @@ urls.db = "/db" urls.query = "/queries?q=" urls.update = "/updates?q=" urls.fortune = "/fortunes" +urls.cached_query = "/cached-queries?q=" approach = "Realistic" classification = "Fullstack" database = "Postgres" @@ -16,4 +17,4 @@ os = "Linux" orm = "Raw" platform = "Rust" webserver = "Hyper" -versus = "None" \ No newline at end of file +versus = "None" diff --git a/frameworks/Rust/axum/src/common/mod.rs b/frameworks/Rust/axum/src/common/mod.rs new file mode 100644 index 00000000000..d55958155f1 --- /dev/null +++ b/frameworks/Rust/axum/src/common/mod.rs @@ -0,0 +1,51 @@ +use std::{env, str::FromStr}; + +use core::fmt::Debug; +use rand::{distributions::Uniform, rngs::SmallRng, Rng}; +pub mod models; +pub mod utils; + +#[cfg(feature = "simd-json")] +pub mod simd_json; + +#[allow(dead_code)] +pub const SELECT_ALL_FORTUNES: &str = "SELECT * FROM fortune"; +#[allow(dead_code)] +pub const SELECT_WORLD_BY_ID: &str = + "SELECT id, randomnumber FROM world WHERE id = $1 LIMIT 1"; +#[allow(dead_code)] +pub const SELECT_ALL_CACHED_WORLDS: &str = + "SELECT id, randomnumber FROM world ORDER BY id"; +#[allow(dead_code)] +pub const UPDATE_WORLDS: &str = "WITH vals AS (SELECT * FROM UNNEST($1::int[], $2::int[]) AS v(id, rnum)) + UPDATE world SET randomnumber = new.rnum FROM + (SELECT w.id, v.rnum FROM world w INNER JOIN vals v ON v.id = w.id ORDER BY w.id FOR UPDATE) AS new + WHERE world.id = new.id"; + +/// Return the value of an environment variable. +#[allow(dead_code)] +pub fn get_env(key: &str) -> T +where + ::Err: Debug, +{ + env::var(key) + .unwrap_or_else(|_| panic!("{key} environment variable was not set")) + .parse::() + .unwrap_or_else(|_| panic!("could not parse {key}")) +} + +/// Generate a single integer in the range 1 to 10,000 (inclusive) +#[allow(dead_code)] +#[inline] +pub fn random_id(rng: &mut SmallRng) -> i32 { + rng.gen_range(1..10_001) +} + +/// Generate vector of integers in the range 1 to 10,000 (inclusive) +#[allow(dead_code)] +#[inline] +pub fn random_ids(rng: &mut SmallRng, count: usize) -> Vec { + rng.sample_iter(Uniform::new(1, 10_001)) + .take(count) + .collect() +} diff --git a/frameworks/Rust/axum/src/models_mongo.rs b/frameworks/Rust/axum/src/common/models.rs similarity index 85% rename from frameworks/Rust/axum/src/models_mongo.rs rename to frameworks/Rust/axum/src/common/models.rs index 31c76cc7c07..1644447c3cd 100644 --- a/frameworks/Rust/axum/src/models_mongo.rs +++ b/frameworks/Rust/axum/src/common/models.rs @@ -1,5 +1,10 @@ use serde::{Deserialize, Serialize}; +#[derive(Serialize)] +pub struct Message { + pub message: &'static str, +} + #[derive(Clone, Debug, PartialEq, Deserialize, Serialize)] pub struct Fortune { pub id: i32, diff --git a/frameworks/Rust/axum/src/common/simd_json.rs b/frameworks/Rust/axum/src/common/simd_json.rs new file mode 100644 index 00000000000..e8a2aafeee1 --- /dev/null +++ b/frameworks/Rust/axum/src/common/simd_json.rs @@ -0,0 +1,152 @@ +use axum::extract::rejection::JsonRejection::MissingJsonContentType; +use axum::extract::Request; +use axum::extract::{rejection::*, FromRequest}; +use axum::{async_trait, http}; +use axum_core::response::{IntoResponse, Response}; +use bytes::{BufMut, Bytes, BytesMut}; +use http::{ + header::{self, HeaderMap, HeaderValue}, + StatusCode, +}; +use serde::{de::DeserializeOwned, Serialize}; +use simd_json; + +#[derive(Debug, Clone, Copy, Default)] +pub struct Json(pub T); + +pub enum SimdJsonRejection { + Json(JsonRejection), + Bytes(BytesRejection), + Simd(String), +} + +impl IntoResponse for SimdJsonRejection { + fn into_response(self) -> Response { + todo!() + } +} + +impl From for SimdJsonRejection { + fn from(err: JsonRejection) -> Self { + SimdJsonRejection::Json(err) + } +} + +impl From for SimdJsonRejection { + fn from(err: BytesRejection) -> Self { + SimdJsonRejection::Bytes(err) + } +} + +impl From for SimdJsonRejection { + fn from(err: simd_json::Error) -> Self { + SimdJsonRejection::Simd(err.to_string()) + } +} + +#[async_trait] +impl FromRequest for Json +where + T: DeserializeOwned, + S: Send + Sync, +{ + type Rejection = SimdJsonRejection; + + async fn from_request(req: Request, state: &S) -> Result { + if json_content_type(req.headers()) { + let bytes = Bytes::from_request(req, state).await?; + Self::from_bytes(&bytes) + } else { + Err(SimdJsonRejection::Json(MissingJsonContentType( + axum::extract::rejection::MissingJsonContentType::default(), + ))) + } + } +} + +fn json_content_type(headers: &HeaderMap) -> bool { + let content_type = if let Some(content_type) = headers.get(header::CONTENT_TYPE) { + content_type + } else { + return false; + }; + + let content_type = if let Ok(content_type) = content_type.to_str() { + content_type + } else { + return false; + }; + + let mime = if let Ok(mime) = content_type.parse::() { + mime + } else { + return false; + }; + + let is_json_content_type = mime.type_() == "application" + && (mime.subtype() == "json" + || mime.suffix().map_or(false, |name| name == "json")); + + is_json_content_type +} + +axum_core::__impl_deref!(Json); + +impl From for Json { + fn from(inner: T) -> Self { + Self(inner) + } +} + +impl Json +where + T: DeserializeOwned, +{ + /// Construct a `Json` from a byte slice. Most users should prefer to use the `FromRequest` impl + /// but special cases may require first extracting a `Request` into `Bytes` then optionally + /// constructing a `Json`. + pub fn from_bytes(bytes: &[u8]) -> Result { + let body = &mut bytes.to_owned(); + let deserializer = simd_json::from_slice::(body); + + let value = match deserializer { + Ok(v) => v, + Err(err) => { + let rejection = { SimdJsonRejection::from(err) }; + return Err(rejection); + } + }; + + Ok(Json(value)) + } +} + +impl IntoResponse for Json +where + T: Serialize, +{ + fn into_response(self) -> Response { + // Use a small initial capacity of 128 bytes like serde_json::to_vec + // https://docs.rs/serde_json/1.0.82/src/serde_json/ser.rs.html#2189 + let mut buf = BytesMut::with_capacity(128).writer(); + match simd_json::to_writer(&mut buf, &self.0) { + Ok(()) => ( + [( + header::CONTENT_TYPE, + HeaderValue::from_static(mime::APPLICATION_JSON.as_ref()), + )], + buf.into_inner().freeze(), + ) + .into_response(), + Err(err) => ( + StatusCode::INTERNAL_SERVER_ERROR, + [( + header::CONTENT_TYPE, + HeaderValue::from_static(mime::TEXT_PLAIN_UTF_8.as_ref()), + )], + err.to_string(), + ) + .into_response(), + } + } +} diff --git a/frameworks/Rust/axum/src/utils.rs b/frameworks/Rust/axum/src/common/utils.rs similarity index 65% rename from frameworks/Rust/axum/src/utils.rs rename to frameworks/Rust/axum/src/common/utils.rs index 89ecaeae6ab..063411f3da7 100644 --- a/frameworks/Rust/axum/src/utils.rs +++ b/frameworks/Rust/axum/src/common/utils.rs @@ -1,35 +1,17 @@ -use std::{env, fmt::Debug, str::FromStr}; - use axum::{ - body::{Bytes, Full}, + body::Bytes, http::{header, HeaderValue, StatusCode}, response::{IntoResponse, Response}, }; -use rand::{rngs::SmallRng, Rng}; use serde::Deserialize; -pub fn get_environment_variable(key: &str) -> T -where - ::Err: Debug, -{ - env::var(key) - .unwrap_or_else(|_| panic!("{key} environment variable was not set")) - .parse::() - .unwrap_or_else(|_| panic!("could not parse {key}")) -} - #[derive(Debug, Deserialize)] pub struct Params { queries: Option, } #[allow(dead_code)] -pub fn random_number(rng: &mut SmallRng) -> i32 { - (rng.gen::() % 10_000 + 1) as i32 -} - -#[allow(dead_code)] -pub fn parse_params(params: Params) -> i32 { +pub fn parse_params(params: Params) -> usize { params .queries .and_then(|q| q.parse().ok()) @@ -52,7 +34,7 @@ pub struct Utf8Html(pub T); impl IntoResponse for Utf8Html where - T: Into>, + T: Into, { fn into_response(self) -> Response { let mut res = (StatusCode::OK, self.0.into()).into_response(); diff --git a/frameworks/Rust/axum/src/database_pg.rs b/frameworks/Rust/axum/src/database_pg.rs deleted file mode 100644 index 56e07553af3..00000000000 --- a/frameworks/Rust/axum/src/database_pg.rs +++ /dev/null @@ -1,199 +0,0 @@ -use std::{collections::HashMap, convert::Infallible, fmt::Write, io, sync::Arc}; - -use axum::{async_trait, extract::FromRequestParts, http::request::Parts}; -use futures::{ - stream::futures_unordered::FuturesUnordered, FutureExt, StreamExt, TryStreamExt, -}; -use rand::{rngs::SmallRng, thread_rng, Rng, SeedableRng}; -use tokio::pin; -use tokio_postgres::{connect, types::ToSql, Client, NoTls, Statement}; - -use crate::models_pg::{Fortune, World}; - -#[derive(Debug)] -pub enum PgError { - Io(io::Error), - Pg(tokio_postgres::Error), -} - -impl From for PgError { - fn from(err: io::Error) -> Self { - PgError::Io(err) - } -} - -impl From for PgError { - fn from(err: tokio_postgres::Error) -> Self { - PgError::Pg(err) - } -} - -/// Postgres interface -pub struct PgConnection { - client: Client, - fortune: Statement, - world: Statement, - updates: HashMap, -} - -impl PgConnection { - pub async fn connect(db_url: String) -> Arc { - let (cl, conn) = connect(&db_url, NoTls) - .await - .expect("can not connect to postgresql"); - - // Spawn connection - tokio::spawn(async move { - if let Err(error) = conn.await { - eprintln!("Connection error: {error}"); - } - }); - - let fortune = cl.prepare("SELECT * FROM fortune").await.unwrap(); - let mut updates = HashMap::new(); - - for num in 1..=500u16 { - let mut pl = 1; - let mut q = String::new(); - - q.push_str("UPDATE world SET randomnumber = CASE id "); - - for _ in 1..=num { - let _ = write!(q, "when ${pl} then ${} ", pl + 1); - pl += 2; - } - - q.push_str("ELSE randomnumber END WHERE id IN ("); - - for _ in 1..=num { - let _ = write!(q, "${pl},"); - pl += 1; - } - - q.pop(); - q.push(')'); - - updates.insert(num, cl.prepare(&q).await.unwrap()); - } - - let world = cl.prepare("SELECT * FROM world WHERE id=$1").await.unwrap(); - - Arc::new(PgConnection { - client: cl, - fortune, - world, - updates, - }) - } -} - -impl PgConnection { - async fn query_one_world(&self, id: i32) -> Result { - let stream = self.client.query_raw(&self.world, &[&id]).await?; - pin!(stream); - let row = stream.next().await.unwrap()?; - Ok(World { - id: row.get(0), - randomnumber: row.get(1), - }) - } - - pub async fn get_world(&self) -> Result { - let mut rng = SmallRng::from_rng(&mut thread_rng()).unwrap(); - - let random_id = (rng.gen::() % 10_000 + 1) as i32; - - let world = self.query_one_world(random_id).await?; - Ok(world) - } - - pub async fn get_worlds(&self, num: usize) -> Result, PgError> { - let mut rng = SmallRng::from_rng(&mut thread_rng()).unwrap(); - - let worlds = FuturesUnordered::new(); - - for _ in 0..num { - let w_id = (rng.gen::() % 10_000 + 1) as i32; - worlds.push(self.query_one_world(w_id)); - } - - worlds.try_collect().await - } - - pub async fn update(&self, num: u16) -> Result, PgError> { - let mut rng = SmallRng::from_rng(&mut thread_rng()).unwrap(); - - let worlds = FuturesUnordered::new(); - - for _ in 0..num { - let id = (rng.gen::() % 10_000 + 1) as i32; - let w_id = (rng.gen::() % 10_000 + 1) as i32; - - worlds.push(self.query_one_world(w_id).map(move |res| match res { - Ok(mut world) => { - world.randomnumber = id; - Ok(world) - } - - Err(err) => Err(err), - })); - } - - let st = self.updates.get(&num).unwrap().clone(); - - let worlds: Vec = worlds.try_collect().await?; - - let mut params: Vec<&(dyn ToSql + Sync)> = Vec::with_capacity(num as usize * 3); - - for w in &worlds { - params.push(&w.id); - params.push(&w.randomnumber); - } - - for w in &worlds { - params.push(&w.id); - } - - self.client.query(&st, ¶ms[..]).await?; - - Ok(worlds) - } - - pub async fn tell_fortune(&self) -> Result, PgError> { - let mut items = vec![Fortune { - id: 0, - message: "Additional fortune added at request time.".parse().unwrap(), - }]; - - let fut = self.client.query_raw::<_, _, &[i32; 0]>(&self.fortune, &[]); - - let stream = fut.await?; - pin!(stream); - - while let Some(row) = stream.next().await { - let row = row?; - - items.push(Fortune { - id: row.get(0), - message: row.get(1), - }); - } - - items.sort_by(|it, next| it.message.cmp(&next.message)); - Ok(items) - } -} - -pub struct DatabaseConnection(pub Arc); - -#[async_trait] -impl FromRequestParts> for DatabaseConnection { - type Rejection = Infallible; - - async fn from_request_parts( - _parts: &mut Parts, - pg_connection: &Arc, - ) -> Result { - Ok(Self(pg_connection.clone())) - } -} diff --git a/frameworks/Rust/axum/src/database_sqlx.rs b/frameworks/Rust/axum/src/database_sqlx.rs deleted file mode 100644 index b156bb3a3b7..00000000000 --- a/frameworks/Rust/axum/src/database_sqlx.rs +++ /dev/null @@ -1,86 +0,0 @@ -use std::io; - -use axum::{ - async_trait, - extract::FromRequestParts, - http::{request::Parts, StatusCode}, -}; -use sqlx::{ - pool::PoolConnection, - postgres::{PgArguments, PgPoolOptions}, - Arguments, PgPool, Postgres, -}; - -use crate::{utils::internal_error, Fortune, World}; - -#[derive(Debug)] -pub enum PgError { - Io(io::Error), - Pg(sqlx::Error), -} - -impl From for PgError { - fn from(err: io::Error) -> Self { - PgError::Io(err) - } -} - -impl From for PgError { - fn from(err: sqlx::Error) -> Self { - PgError::Pg(err) - } -} - -pub async fn create_pool( - database_url: String, - max_pool_size: u32, - min_pool_size: u32, -) -> PgPool { - PgPoolOptions::new() - .max_connections(max_pool_size) - .min_connections(min_pool_size) - .connect(&database_url) - .await - .unwrap() -} - -pub struct DatabaseConnection(pub PoolConnection); - -#[async_trait] -impl FromRequestParts for DatabaseConnection { - type Rejection = (StatusCode, String); - - async fn from_request_parts( - _parts: &mut Parts, - pool: &PgPool, - ) -> Result { - let conn = pool.acquire().await.map_err(internal_error)?; - - Ok(Self(conn)) - } -} - -pub async fn fetch_world( - mut conn: PoolConnection, - number: i32, -) -> Result { - let mut args = PgArguments::default(); - args.add(number); - - let world: World = - sqlx::query_as_with("SELECT id, randomnumber FROM World WHERE id = $1", args) - .fetch_one(&mut *conn) - .await - .expect("error loading world"); - Ok(world) -} - -pub async fn fetch_fortunes( - mut conn: PoolConnection, -) -> Result, PgError> { - let fortunes: Vec = sqlx::query_as("SELECT * FROM Fortune") - .fetch_all(&mut *conn) - .await - .expect("error loading Fortunes"); - Ok(fortunes) -} diff --git a/frameworks/Rust/axum/src/main.rs b/frameworks/Rust/axum/src/main.rs index 075ee1c01e6..b29da958d20 100644 --- a/frameworks/Rust/axum/src/main.rs +++ b/frameworks/Rust/axum/src/main.rs @@ -1,21 +1,21 @@ -use axum::{ - http::{header, HeaderValue, StatusCode}, - response::IntoResponse, - routing::get, - Json, Router, -}; -use dotenv::dotenv; -use tower_http::set_header::SetResponseHeaderLayer; - -mod models_common; +mod common; mod server; -use self::models_common::Message; +use axum::{http::StatusCode, response::IntoResponse, routing::get, Router}; +use common::models::Message; +use dotenv::dotenv; + +#[cfg(not(feature = "simd-json"))] +use axum::Json; +#[cfg(feature = "simd-json")] +use common::simd_json::Json; -pub async fn plaintext() -> &'static str { - "Hello, World!" +/// Return a plaintext static string. +pub async fn plaintext() -> impl IntoResponse { + (StatusCode::OK, "Hello, World!") } +/// Return a JSON message. pub async fn json() -> impl IntoResponse { let message = Message { message: "Hello, World!", @@ -28,19 +28,9 @@ pub async fn json() -> impl IntoResponse { async fn main() { dotenv().ok(); - let server_header_value = HeaderValue::from_static("Axum"); - let app = Router::new() .route("/plaintext", get(plaintext)) - .route("/json", get(json)) - .layer(SetResponseHeaderLayer::if_not_present( - header::SERVER, - server_header_value, - )); - - server::builder() - .http1_pipeline_flush(true) - .serve(app.into_make_service()) - .await - .unwrap(); + .route("/json", get(json)); + + server::serve_hyper(app, Some(8000)).await } diff --git a/frameworks/Rust/axum/src/main_mongo.rs b/frameworks/Rust/axum/src/main_mongo.rs index 8219113f583..8f7ac7961c3 100644 --- a/frameworks/Rust/axum/src/main_mongo.rs +++ b/frameworks/Rust/axum/src/main_mongo.rs @@ -1,11 +1,20 @@ +mod common; +mod mongo; +//mod mongo_raw; + use std::time::Duration; use axum::{ - extract::Query, - http::{header, HeaderValue, StatusCode}, - response::IntoResponse, - routing::get, - Json, Router, + extract::Query, http::StatusCode, response::IntoResponse, routing::get, Router, +}; + +#[cfg(not(feature = "simd-json"))] +use axum::Json; +#[cfg(feature = "simd-json")] +use common::simd_json::Json; +use common::{ + models::{FortuneInfo, World}, + random_ids, }; use dotenv::dotenv; use mongodb::{ @@ -13,21 +22,16 @@ use mongodb::{ Client, }; use rand::{rngs::SmallRng, thread_rng, Rng, SeedableRng}; -use tower_http::set_header::SetResponseHeaderLayer; use yarte::Template; -mod database_mongo; -mod models_common; -mod models_mongo; mod server; -mod utils; - -use self::{ - database_mongo::{ - fetch_fortunes, find_world_by_id, find_worlds, update_worlds, DatabaseConnection, - }, - models_mongo::{Fortune, FortuneInfo, World}, - utils::{get_environment_variable, parse_params, Params, Utf8Html}, + +use common::{ + get_env, + utils::{parse_params, Params, Utf8Html}, +}; +use mongo::database::{ + fetch_fortunes, find_world_by_id, find_worlds, update_worlds, DatabaseConnection, }; #[derive(Template)] @@ -55,13 +59,7 @@ async fn queries( let q = parse_params(params); let mut rng = SmallRng::from_rng(&mut thread_rng()).unwrap(); - let mut ids: Vec = Vec::with_capacity(q as usize); - - for _ in 0..q { - let random_id = (rng.gen::() % 10_000 + 1) as i32; - - ids.push(random_id); - } + let ids = random_ids(&mut rng, q); let worlds = find_worlds(db, ids).await; let results = worlds.expect("worlds could not be retrieved"); @@ -76,18 +74,12 @@ async fn updates( let q = parse_params(params); let mut rng = SmallRng::from_rng(&mut thread_rng()).unwrap(); - let mut ids: Vec = Vec::with_capacity(q as usize); - - for _ in 0..q { - let random_id = (rng.gen::() % 10_000 + 1) as i32; - - ids.push(random_id); - } + let ids = random_ids(&mut rng, q); let worlds = find_worlds(db.clone(), ids) .await .expect("worlds could not be retrieved"); - let mut updated_worlds: Vec = Vec::with_capacity(q as usize); + let mut updated_worlds: Vec = Vec::with_capacity(q); for mut world in worlds { let random_number = (rng.gen::() % 10_000 + 1) as i32; @@ -144,9 +136,9 @@ fn main() { } async fn serve() { - let database_url: String = get_environment_variable("AXUM_TECHEMPOWER_MONGODB_URL"); - let max_pool_size: u32 = get_environment_variable("AXUM_TECHEMPOWER_MAX_POOL_SIZE"); - let min_pool_size: u32 = get_environment_variable("AXUM_TECHEMPOWER_MIN_POOL_SIZE"); + let database_url: String = get_env("MONGODB_URL"); + let max_pool_size: u32 = get_env("MONGODB_MAX_POOL_SIZE"); + let min_pool_size: u32 = get_env("MONGODB_MIN_POOL_SIZE"); let mut client_options = ClientOptions::parse(database_url).await.unwrap(); @@ -168,21 +160,13 @@ async fn serve() { let client = Client::with_options(client_options).unwrap(); let database = client.database("hello_world"); - let server_header_value = HeaderValue::from_static("Axum"); let app = Router::new() .route("/fortunes", get(fortunes)) .route("/db", get(db)) .route("/queries", get(queries)) .route("/updates", get(updates)) - .with_state(database) - .layer(SetResponseHeaderLayer::if_not_present( - header::SERVER, - server_header_value, - )); - - server::builder() - .serve(app.into_make_service()) - .await - .unwrap(); + .with_state(database); + + server::serve(app, Some(8000)).await } diff --git a/frameworks/Rust/axum/src/main_mongo_raw.rs b/frameworks/Rust/axum/src/main_mongo_raw.rs index 72db28af280..fdf09c179a3 100644 --- a/frameworks/Rust/axum/src/main_mongo_raw.rs +++ b/frameworks/Rust/axum/src/main_mongo_raw.rs @@ -1,38 +1,38 @@ +mod common; +mod mongo_raw; +mod server; + +use common::{models::World, random_id, random_ids}; +use mongo_raw::database::{ + find_world_by_id, find_worlds, update_worlds, DatabaseConnection, +}; + +use common::{ + get_env, + utils::{parse_params, Params}, +}; use std::time::Duration; use axum::{ - extract::Query, - http::{header, HeaderValue, StatusCode}, - response::IntoResponse, - routing::get, - Json, Router, + extract::Query, http::StatusCode, response::IntoResponse, routing::get, Router, }; + +#[cfg(not(feature = "simd-json"))] +use axum::Json; +#[cfg(feature = "simd-json")] +use common::simd_json::Json; + use dotenv::dotenv; use mongodb::{ options::{ClientOptions, Compressor}, Client, }; use rand::{rngs::SmallRng, thread_rng, Rng, SeedableRng}; -use tower_http::set_header::SetResponseHeaderLayer; - -mod database_mongo_raw; -mod models_common; -mod models_mongo; -mod server; -mod utils; - -use self::{ - database_mongo_raw::{ - find_world_by_id, find_worlds, update_worlds, DatabaseConnection, - }, - models_mongo::World, - utils::{get_environment_variable, parse_params, Params}, -}; async fn db(DatabaseConnection(db): DatabaseConnection) -> impl IntoResponse { let mut rng = SmallRng::from_rng(&mut thread_rng()).unwrap(); - let random_id = (rng.gen::() % 10_000 + 1) as i32; + let random_id = random_id(&mut rng); let world = find_world_by_id(db, random_id) .await @@ -48,13 +48,7 @@ async fn queries( let q = parse_params(params); let mut rng = SmallRng::from_rng(&mut thread_rng()).unwrap(); - let mut ids: Vec = Vec::with_capacity(q as usize); - - for _ in 0..q { - let random_id = (rng.gen::() % 10_000 + 1) as i32; - - ids.push(random_id); - } + let ids = random_ids(&mut rng, q); let worlds = find_worlds(db, ids).await; let results = worlds.expect("worlds could not be retrieved"); @@ -69,18 +63,12 @@ async fn updates( let q = parse_params(params); let mut rng = SmallRng::from_rng(&mut thread_rng()).unwrap(); - let mut ids: Vec = Vec::with_capacity(q as usize); - - for _ in 0..q { - let random_id = (rng.gen::() % 10_000 + 1) as i32; - - ids.push(random_id); - } + let ids = random_ids(&mut rng, q); let worlds = find_worlds(db.clone(), ids) .await .expect("worlds could not be retrieved"); - let mut updated_worlds: Vec = Vec::with_capacity(q as usize); + let mut updated_worlds: Vec = Vec::with_capacity(q); for mut world in worlds { let random_number = (rng.gen::() % 10_000 + 1) as i32; @@ -117,9 +105,9 @@ fn main() { } async fn serve() { - let database_url: String = get_environment_variable("AXUM_TECHEMPOWER_MONGODB_URL"); - let max_pool_size: u32 = get_environment_variable("AXUM_TECHEMPOWER_MAX_POOL_SIZE"); - let min_pool_size: u32 = get_environment_variable("AXUM_TECHEMPOWER_MIN_POOL_SIZE"); + let database_url: String = get_env("MONGODB_URL"); + let max_pool_size: u32 = get_env("MONGODB_MAX_POOL_SIZE"); + let min_pool_size: u32 = get_env("MONGODB_MIN_POOL_SIZE"); let mut client_options = ClientOptions::parse(database_url).await.unwrap(); @@ -141,20 +129,12 @@ async fn serve() { let client = Client::with_options(client_options).unwrap(); let database = client.database("hello_world"); - let server_header_value = HeaderValue::from_static("Axum"); let app = Router::new() .route("/db", get(db)) .route("/queries", get(queries)) .route("/updates", get(updates)) - .with_state(database) - .layer(SetResponseHeaderLayer::if_not_present( - header::SERVER, - server_header_value, - )); - - server::builder() - .serve(app.into_make_service()) - .await - .unwrap(); + .with_state(database); + + server::serve(app, Some(8000)).await } diff --git a/frameworks/Rust/axum/src/main_pg.rs b/frameworks/Rust/axum/src/main_pg.rs index 3b4748dfc39..20acb2a1769 100644 --- a/frameworks/Rust/axum/src/main_pg.rs +++ b/frameworks/Rust/axum/src/main_pg.rs @@ -1,25 +1,26 @@ +mod common; +mod pg; + use axum::{ - extract::Query, - http::{header, HeaderValue, StatusCode}, - response::IntoResponse, - routing::get, - Json, Router, + extract::Query, http::StatusCode, response::IntoResponse, routing::get, Router, }; use dotenv::dotenv; -use tower_http::set_header::SetResponseHeaderLayer; +use rand::{rngs::SmallRng, thread_rng, SeedableRng}; use yarte::Template; -mod database_pg; -mod models_common; -mod models_pg; +#[cfg(not(feature = "simd-json"))] +use axum::Json; +#[cfg(feature = "simd-json")] +use common::simd_json::Json; + mod server; -mod utils; -use self::{ - database_pg::{DatabaseConnection, PgConnection}, - models_pg::Fortune, - utils::{get_environment_variable, parse_params, Params, Utf8Html}, +use common::{ + get_env, random_id, + utils::{parse_params, Params, Utf8Html}, }; +use pg::database::{DatabaseConnection, PgConnection}; +use pg::models::Fortune; #[derive(Template)] #[template(path = "fortunes.html.hbs")] @@ -28,7 +29,12 @@ pub struct FortunesTemplate<'a> { } async fn db(DatabaseConnection(conn): DatabaseConnection) -> impl IntoResponse { - let world = conn.get_world().await.expect("error loading world"); + let mut rng = SmallRng::from_rng(&mut thread_rng()).unwrap(); + + let world = conn + .fetch_world_by_id(random_id(&mut rng)) + .await + .expect("error loading world"); (StatusCode::OK, Json(world)) } @@ -40,7 +46,7 @@ async fn queries( let q = parse_params(params); let results = conn - .get_worlds(q as usize) + .fetch_random_worlds(q) .await .expect("error loading worlds"); @@ -48,8 +54,10 @@ async fn queries( } async fn fortunes(DatabaseConnection(conn): DatabaseConnection) -> impl IntoResponse { - let fortunes: Vec = - conn.tell_fortune().await.expect("error loading fortunes"); + let fortunes: Vec = conn + .fetch_all_fortunes() + .await + .expect("error loading fortunes"); Utf8Html( FortunesTemplate { @@ -65,52 +73,26 @@ async fn updates( Query(params): Query, ) -> impl IntoResponse { let q = parse_params(params); + let worlds = conn.update_worlds(q).await.expect("error updating worlds"); - let results = conn.update(q as u16).await.expect("error updating worlds"); - - (StatusCode::OK, Json(results)) + (StatusCode::OK, Json(worlds)) } -fn main() { +#[tokio::main] +async fn main() { dotenv().ok(); - let rt = tokio::runtime::Builder::new_current_thread() - .enable_all() - .build() - .unwrap(); - - for _ in 1..num_cpus::get() { - std::thread::spawn(move || { - let rt = tokio::runtime::Builder::new_current_thread() - .enable_all() - .build() - .unwrap(); - rt.block_on(serve()); - }); - } - rt.block_on(serve()); -} - -async fn serve() { - let database_url: String = get_environment_variable("AXUM_TECHEMPOWER_DATABASE_URL"); + let database_url: String = get_env("POSTGRES_URL"); - // setup connection pool + // Create shared database connection let pg_connection = PgConnection::connect(database_url).await; - let server_header_value = HeaderValue::from_static("Axum"); - let router = Router::new() + let app = Router::new() .route("/fortunes", get(fortunes)) .route("/db", get(db)) .route("/queries", get(queries)) .route("/updates", get(updates)) - .with_state(pg_connection) - .layer(SetResponseHeaderLayer::if_not_present( - header::SERVER, - server_header_value, - )); - - server::builder() - .serve(router.into_make_service()) - .await - .unwrap(); + .with_state(pg_connection); + + server::serve_hyper(app, Some(8000)).await } diff --git a/frameworks/Rust/axum/src/main_pg_pool.rs b/frameworks/Rust/axum/src/main_pg_pool.rs index 4c767b4a06c..d4b7754cba8 100644 --- a/frameworks/Rust/axum/src/main_pg_pool.rs +++ b/frameworks/Rust/axum/src/main_pg_pool.rs @@ -1,31 +1,31 @@ +mod common; +mod pg_pool; + use axum::{ - extract::Query, - http::{header, HeaderValue, StatusCode}, - response::IntoResponse, - routing::get, - Json, Router, + extract::Query, http::StatusCode, response::IntoResponse, routing::get, Router, }; + +#[cfg(not(feature = "simd-json"))] +use axum::Json; +#[cfg(feature = "simd-json")] +use common::simd_json::Json; + +use common::{random_ids, SELECT_ALL_FORTUNES, SELECT_WORLD_BY_ID, UPDATE_WORLDS}; use dotenv::dotenv; use futures_util::{stream::FuturesUnordered, TryStreamExt}; -use rand::{rngs::SmallRng, thread_rng, Rng, SeedableRng}; -use tower_http::set_header::SetResponseHeaderLayer; +use rand::{rngs::SmallRng, thread_rng, SeedableRng}; use yarte::Template; -mod database_pg_pool; -mod models_common; -mod models_pg_pool; mod server; -mod utils; - -use self::{ - database_pg_pool::{ - create_pool, fetch_all_fortunes, fetch_world_by_id, - prepare_fetch_all_fortunes_statement, prepare_fetch_world_by_id_statement, - prepare_update_world_by_id_statement, update_world, DatabaseClient, PgError, - }, - models_pg_pool::{Fortune, World}, - utils::{get_environment_variable, parse_params, random_number, Params, Utf8Html}, + +use common::{ + get_env, random_id, + utils::{parse_params, Params, Utf8Html}, }; +use pg_pool::database::{ + create_pool, fetch_all_fortunes, fetch_world_by_id, DatabaseClient, PgError, +}; +use pg_pool::models::{Fortune, World}; #[derive(Template)] #[template(path = "fortunes.html.hbs")] @@ -35,11 +35,10 @@ pub struct FortunesTemplate<'a> { async fn db(DatabaseClient(client): DatabaseClient) -> impl IntoResponse { let mut rng = SmallRng::from_rng(&mut thread_rng()).unwrap(); + let random_id = random_id(&mut rng); - let random_id = (rng.gen::() % 10_000 + 1) as i32; - - let select = prepare_fetch_world_by_id_statement(&client).await; - let world = fetch_world_by_id(&client, random_id, &select) + let select = &client.prepare_cached(SELECT_WORLD_BY_ID).await.unwrap(); + let world = fetch_world_by_id(&client, random_id, select) .await .expect("could not fetch world"); @@ -53,15 +52,11 @@ async fn queries( let q = parse_params(params); let mut rng = SmallRng::from_rng(&mut thread_rng()).unwrap(); - - let select = prepare_fetch_world_by_id_statement(&client).await; - + let select = &client.prepare_cached(SELECT_WORLD_BY_ID).await.unwrap(); let future_worlds = FuturesUnordered::new(); - for _ in 0..q { - let w_id = (rng.gen::() % 10_000 + 1) as i32; - - future_worlds.push(fetch_world_by_id(&client, w_id, &select)); + for id in random_ids(&mut rng, q) { + future_worlds.push(fetch_world_by_id(&client, id, select)); } let worlds: Result, PgError> = future_worlds.try_collect().await; @@ -71,9 +66,9 @@ async fn queries( } async fn fortunes(DatabaseClient(client): DatabaseClient) -> impl IntoResponse { - let select = prepare_fetch_all_fortunes_statement(&client).await; + let select = &client.prepare_cached(SELECT_ALL_FORTUNES).await.unwrap(); - let mut fortunes = fetch_all_fortunes(client, &select) + let mut fortunes = fetch_all_fortunes(client, select) .await .expect("could not fetch fortunes"); @@ -100,66 +95,49 @@ async fn updates( let q = parse_params(params); let mut rng = SmallRng::from_entropy(); + let select = &client.prepare_cached(SELECT_WORLD_BY_ID).await.unwrap(); + let update = &client.prepare_cached(UPDATE_WORLDS).await.unwrap(); - let select = prepare_fetch_world_by_id_statement(&client).await; - + // Select the random worlds. let future_worlds = FuturesUnordered::new(); - - for _ in 0..q { - let query_id = random_number(&mut rng); - - future_worlds.push(fetch_world_by_id(&client, query_id, &select)); + for id in random_ids(&mut rng, q) { + future_worlds.push(fetch_world_by_id(&client, id, select)); } - - let worlds: Result, PgError> = future_worlds.try_collect().await; - let results = worlds.expect("worlds could not be retrieved"); - - let update = prepare_update_world_by_id_statement(&client).await; - - let future_world_updates = FuturesUnordered::new(); - - for w in &results { - let random_id = random_number(&mut rng); - let w_id = w.id; - - future_world_updates.push(update_world(&client, &update, random_id, w_id)); - } - - let world_updates: Result, PgError> = - future_world_updates.try_collect().await; - world_updates.expect("updates could not be executed"); - - (StatusCode::OK, Json(results)) + let worlds: Vec = future_worlds.try_collect().await.unwrap(); + + let mut ids = Vec::with_capacity(q); + let mut nids = Vec::with_capacity(q); + let worlds: Vec = worlds + .into_iter() + .map(|mut w| { + w.randomnumber = random_id(&mut rng); + ids.push(w.id); + nids.push(w.randomnumber); + w + }) + .collect(); + + // Update the random worlds in the database. + client.execute(update, &[&ids, &nids]).await.unwrap(); + + (StatusCode::OK, Json(worlds)) } #[tokio::main] async fn main() { dotenv().ok(); - serve().await; -} - -async fn serve() { - let database_url: String = get_environment_variable("AXUM_TECHEMPOWER_DATABASE_URL"); - let max_pool_size: u32 = get_environment_variable("AXUM_TECHEMPOWER_MAX_POOL_SIZE"); + let database_url: String = get_env("POSTGRES_URL"); + let max_pool_size: u32 = get_env("POSTGRES_MAX_POOL_SIZE"); - // setup Client pool let pool = create_pool(database_url, max_pool_size).await; - let server_header_value = HeaderValue::from_static("Axum"); - let router = Router::new() + let app = Router::new() .route("/fortunes", get(fortunes)) .route("/db", get(db)) .route("/queries", get(queries)) .route("/updates", get(updates)) - .with_state(pool) - .layer(SetResponseHeaderLayer::if_not_present( - header::SERVER, - server_header_value, - )); - - server::builder() - .serve(router.into_make_service()) - .await - .unwrap(); + .with_state(pool); + + server::serve_hyper(app, Some(8000)).await } diff --git a/frameworks/Rust/axum/src/main_sqlx.rs b/frameworks/Rust/axum/src/main_sqlx.rs index c773233fcfa..d10b1ea99ef 100644 --- a/frameworks/Rust/axum/src/main_sqlx.rs +++ b/frameworks/Rust/axum/src/main_sqlx.rs @@ -1,27 +1,35 @@ +mod common; +mod sqlx; + +use std::sync::Arc; + +use ::sqlx::PgPool; use axum::{ - http::{header, HeaderValue, StatusCode}, + extract::{Query, State}, + http::StatusCode, response::IntoResponse, routing::get, - Json, Router, + Router, }; use dotenv::dotenv; -use rand::{rngs::SmallRng, thread_rng, Rng, SeedableRng}; -use sqlx::PgPool; -use tower_http::set_header::SetResponseHeaderLayer; +use moka::future::Cache; +use rand::{rngs::SmallRng, thread_rng, SeedableRng}; +use sqlx::models::World; use yarte::Template; -mod database_sqlx; -mod models_common; -mod models_sqlx; +#[cfg(not(feature = "simd-json"))] +use axum::Json; +#[cfg(feature = "simd-json")] +use common::simd_json::Json; + mod server; -mod utils; -use self::{ - database_sqlx::{create_pool, fetch_fortunes, fetch_world, DatabaseConnection}, - models_sqlx::{Fortune, World}, - utils::get_environment_variable, - utils::Utf8Html, +use common::{ + get_env, random_id, random_ids, + utils::{parse_params, Params, Utf8Html}, }; +use sqlx::database::create_pool; +use sqlx::models::Fortune; #[derive(Template)] #[template(path = "fortunes.html.hbs")] @@ -29,22 +37,44 @@ pub struct FortunesTemplate<'a> { pub fortunes: &'a Vec, } -async fn db(DatabaseConnection(conn): DatabaseConnection) -> impl IntoResponse { +async fn db(State(AppState { db, .. }): State) -> impl IntoResponse { let mut rng = SmallRng::from_rng(&mut thread_rng()).unwrap(); - let random_id = (rng.gen::() % 10_000 + 1) as i32; - - let world = fetch_world(conn, random_id) + let world: World = ::sqlx::query_as(common::SELECT_WORLD_BY_ID) + .bind(random_id(&mut rng)) + .fetch_one(&mut *db.acquire().await.unwrap()) .await - .expect("could not fetch world"); + .expect("error loading world"); (StatusCode::OK, Json(world)) } -async fn fortunes(DatabaseConnection(conn): DatabaseConnection) -> impl IntoResponse { - let mut fortunes = fetch_fortunes(conn) +async fn queries( + State(AppState { db, .. }): State, + Query(params): Query, +) -> impl IntoResponse { + let mut rng = SmallRng::from_rng(&mut thread_rng()).unwrap(); + let count = parse_params(params); + let ids = random_ids(&mut rng, count); + let mut worlds: Vec = Vec::with_capacity(count); + + for id in ids { + let world: World = ::sqlx::query_as(common::SELECT_WORLD_BY_ID) + .bind(id) + .fetch_one(&mut *db.acquire().await.unwrap()) + .await + .expect("error loading world"); + worlds.push(world); + } + + (StatusCode::OK, Json(worlds)) +} + +async fn fortunes(State(AppState { db, .. }): State) -> impl IntoResponse { + let mut fortunes: Vec = ::sqlx::query_as(common::SELECT_ALL_FORTUNES) + .fetch_all(&mut *db.acquire().await.unwrap()) .await - .expect("could not fetch fortunes"); + .expect("error loading Fortunes"); fortunes.push(Fortune { id: 0, @@ -62,34 +92,61 @@ async fn fortunes(DatabaseConnection(conn): DatabaseConnection) -> impl IntoResp ) } -#[tokio::main] -async fn main() { - dotenv().ok(); - - let database_url: String = get_environment_variable("AXUM_TECHEMPOWER_DATABASE_URL"); - let max_pool_size: u32 = get_environment_variable("AXUM_TECHEMPOWER_MAX_POOL_SIZE"); - let min_pool_size: u32 = get_environment_variable("AXUM_TECHEMPOWER_MIN_POOL_SIZE"); +async fn cache( + State(AppState { cache, .. }): State, + Query(params): Query, +) -> impl IntoResponse { + let count = parse_params(params); + let mut rng = SmallRng::from_rng(&mut thread_rng()).unwrap(); + let mut worlds: Vec>> = Vec::with_capacity(count); - // setup connection pool - let pool = create_pool(database_url, max_pool_size, min_pool_size).await; + for id in random_ids(&mut rng, count) { + worlds.push(cache.get(&id).await); + } - let app = router(pool).await; + (StatusCode::OK, Json(worlds)) +} - server::builder() - .serve(app.into_make_service()) +/// Pre-load the cache with all worlds. +async fn preload_cache(AppState { db, cache }: &AppState) { + let worlds: Vec = ::sqlx::query_as(common::SELECT_ALL_CACHED_WORLDS) + .fetch_all(&mut *db.acquire().await.unwrap()) .await - .unwrap(); + .expect("error loading worlds"); + + for world in worlds { + cache.insert(world.id, Arc::new(world)).await; + } } -async fn router(pool: PgPool) -> Router { - let server_header_value = HeaderValue::from_static("Axum"); +#[derive(Clone)] +struct AppState { + db: PgPool, + cache: Cache>, +} - Router::new() +#[tokio::main] +async fn main() { + dotenv().ok(); + + let database_url: String = get_env("POSTGRES_URL"); + let max_pool_size: u32 = get_env("POSTGRES_MAX_POOL_SIZE"); + let min_pool_size: u32 = get_env("POSTGRES_MIN_POOL_SIZE"); + + let state = AppState { + db: create_pool(database_url, max_pool_size, min_pool_size).await, + cache: Cache::new(10000), + }; + + // Prime the cache with CachedWorld objects + preload_cache(&state).await; + + let app = Router::new() .route("/fortunes", get(fortunes)) .route("/db", get(db)) - .with_state(pool) - .layer(SetResponseHeaderLayer::if_not_present( - header::SERVER, - server_header_value, - )) + .route("/queries", get(queries)) + .route("/cached-queries", get(cache)) + .with_state(state); + + server::serve_hyper(app, Some(8000)).await } diff --git a/frameworks/Rust/axum/src/models_common.rs b/frameworks/Rust/axum/src/models_common.rs deleted file mode 100644 index 9aed68955a4..00000000000 --- a/frameworks/Rust/axum/src/models_common.rs +++ /dev/null @@ -1,6 +0,0 @@ -use serde::Serialize; - -#[derive(Serialize)] -pub struct Message { - pub message: &'static str, -} diff --git a/frameworks/Rust/axum/src/database_mongo.rs b/frameworks/Rust/axum/src/mongo/database.rs similarity index 97% rename from frameworks/Rust/axum/src/database_mongo.rs rename to frameworks/Rust/axum/src/mongo/database.rs index dcb9b1bebb9..28c55d25c01 100644 --- a/frameworks/Rust/axum/src/database_mongo.rs +++ b/frameworks/Rust/axum/src/mongo/database.rs @@ -4,7 +4,7 @@ use axum::{async_trait, extract::FromRequestParts, http::request::Parts}; use futures_util::{stream::FuturesUnordered, StreamExt, TryStreamExt}; use mongodb::{bson::doc, Database}; -use crate::{Fortune, World}; +use crate::common::models::{Fortune, World}; pub struct DatabaseConnection(pub Database); @@ -21,6 +21,7 @@ impl FromRequestParts for DatabaseConnection { } #[derive(Debug)] +#[allow(dead_code)] pub enum MongoError { Io(io::Error), Mongo(mongodb::error::Error), diff --git a/frameworks/Rust/axum/src/mongo/mod.rs b/frameworks/Rust/axum/src/mongo/mod.rs new file mode 100644 index 00000000000..8fd0a6be869 --- /dev/null +++ b/frameworks/Rust/axum/src/mongo/mod.rs @@ -0,0 +1 @@ +pub mod database; diff --git a/frameworks/Rust/axum/src/database_mongo_raw.rs b/frameworks/Rust/axum/src/mongo_raw/database.rs similarity index 97% rename from frameworks/Rust/axum/src/database_mongo_raw.rs rename to frameworks/Rust/axum/src/mongo_raw/database.rs index 2fa02c07ec4..638c590c9fa 100644 --- a/frameworks/Rust/axum/src/database_mongo_raw.rs +++ b/frameworks/Rust/axum/src/mongo_raw/database.rs @@ -7,7 +7,7 @@ use mongodb::{ Database, }; -use crate::World; +use crate::common::models::World; pub struct DatabaseConnection(pub Database); @@ -24,6 +24,7 @@ impl FromRequestParts for DatabaseConnection { } #[derive(Debug)] +#[allow(dead_code)] pub enum MongoError { Io(io::Error), Mongo(mongodb::error::Error), diff --git a/frameworks/Rust/axum/src/mongo_raw/mod.rs b/frameworks/Rust/axum/src/mongo_raw/mod.rs new file mode 100644 index 00000000000..8fd0a6be869 --- /dev/null +++ b/frameworks/Rust/axum/src/mongo_raw/mod.rs @@ -0,0 +1 @@ +pub mod database; diff --git a/frameworks/Rust/axum/src/pg/database.rs b/frameworks/Rust/axum/src/pg/database.rs new file mode 100644 index 00000000000..bc78b2ba5c8 --- /dev/null +++ b/frameworks/Rust/axum/src/pg/database.rs @@ -0,0 +1,155 @@ +use std::{convert::Infallible, io, sync::Arc}; + +use axum::{async_trait, extract::FromRequestParts, http::request::Parts}; +use futures::{stream::futures_unordered::FuturesUnordered, StreamExt, TryStreamExt}; +use rand::{rngs::SmallRng, thread_rng, SeedableRng}; +use tokio::pin; +use tokio_postgres::{connect, Client, NoTls, Statement}; + +use crate::common::{self, random_id, random_ids}; + +use super::models::{Fortune, World}; + +#[derive(Debug)] +#[allow(dead_code)] +pub enum PgError { + Io(io::Error), + Pg(tokio_postgres::Error), +} + +impl From for PgError { + fn from(err: io::Error) -> Self { + PgError::Io(err) + } +} + +impl From for PgError { + fn from(err: tokio_postgres::Error) -> Self { + PgError::Pg(err) + } +} + +/// Postgres interface +pub struct PgConnection { + client: Client, + fortune: Statement, + world: Statement, + updates: Statement, +} + +impl PgConnection { + pub async fn connect(db_url: String) -> Arc { + let (cl, conn) = connect(&db_url, NoTls) + .await + .expect("cannot connect to postgresql."); + + // Spawn connection + tokio::spawn(async move { + if let Err(error) = conn.await { + eprintln!("database connection error: {error}"); + } + }); + + // Prepare statements for the connection. + let fortune = cl.prepare(common::SELECT_ALL_FORTUNES).await.unwrap(); + let world = cl.prepare(common::SELECT_WORLD_BY_ID).await.unwrap(); + let updates = cl.prepare(common::UPDATE_WORLDS).await.unwrap(); + + Arc::new(PgConnection { + client: cl, + fortune, + world, + updates, + }) + } +} + +impl PgConnection { + pub async fn fetch_world_by_id(&self, id: i32) -> Result { + self.client + .query_one(&self.world, &[&id]) + .await + .map(|row| { + Ok(World { + id: row.get(0), + randomnumber: row.get(1), + }) + })? + } + + pub async fn fetch_random_worlds(&self, num: usize) -> Result, PgError> { + let mut rng = SmallRng::from_rng(&mut thread_rng()).unwrap(); + + let futures = FuturesUnordered::new(); + + for id in random_ids(&mut rng, num) { + futures.push(self.fetch_world_by_id(id)); + } + + futures.try_collect().await + } + + pub async fn update_worlds(&self, num: usize) -> Result, PgError> { + let worlds = self.fetch_random_worlds(num).await?; + + // Update the worlds with new random numbers + let mut rng = SmallRng::from_rng(&mut thread_rng()).unwrap(); + let mut ids = Vec::with_capacity(num); + let mut nids = Vec::with_capacity(num); + let worlds: Vec = worlds + .into_iter() + .map(|mut w| { + w.randomnumber = random_id(&mut rng); + ids.push(w.id); + nids.push(w.randomnumber); + w + }) + .collect(); + + // Update the random worlds in the database. + self.client + .execute(&self.updates, &[&ids, &nids]) + .await + .unwrap(); + + Ok(worlds) + } + + pub async fn fetch_all_fortunes(&self) -> Result, PgError> { + let mut fortunes = vec![Fortune { + id: 0, + message: "Additional fortune added at request time.".parse().unwrap(), + }]; + + let rows = self + .client + .query_raw::<_, _, &[i32; 0]>(&self.fortune, &[]) + .await?; + + pin!(rows); + + while let Some(row) = rows.next().await.transpose()? { + fortunes.push(Fortune { + id: row.get(0), + message: row.get(1), + }); + } + + fortunes.sort_by(|it, next| it.message.cmp(&next.message)); + Ok(fortunes) + } +} + +pub struct DatabaseConnection(pub Arc); + +#[async_trait] +impl FromRequestParts> for DatabaseConnection { + type Rejection = Infallible; + + async fn from_request_parts( + _parts: &mut Parts, + pg_connection: &Arc, + ) -> Result { + Ok(Self(pg_connection.clone())) + } +} diff --git a/frameworks/Rust/axum/src/pg/mod.rs b/frameworks/Rust/axum/src/pg/mod.rs new file mode 100644 index 00000000000..c51e02d23d3 --- /dev/null +++ b/frameworks/Rust/axum/src/pg/mod.rs @@ -0,0 +1,2 @@ +pub mod database; +pub mod models; diff --git a/frameworks/Rust/axum/src/models_pg.rs b/frameworks/Rust/axum/src/pg/models.rs similarity index 100% rename from frameworks/Rust/axum/src/models_pg.rs rename to frameworks/Rust/axum/src/pg/models.rs diff --git a/frameworks/Rust/axum/src/database_pg_pool.rs b/frameworks/Rust/axum/src/pg_pool/database.rs similarity index 60% rename from frameworks/Rust/axum/src/database_pg_pool.rs rename to frameworks/Rust/axum/src/pg_pool/database.rs index f86c002845a..e1a43f34f23 100644 --- a/frameworks/Rust/axum/src/database_pg_pool.rs +++ b/frameworks/Rust/axum/src/pg_pool/database.rs @@ -1,17 +1,22 @@ use std::io; +use crate::{ + common::utils::internal_error, + pg_pool::models::{Fortune, World}, +}; use axum::{ async_trait, extract::FromRequestParts, http::{request::Parts, StatusCode}, }; use deadpool_postgres::{Client, Manager, ManagerConfig, RecyclingMethod}; +use futures_util::StreamExt; +use tokio::pin; use tokio_pg_mapper::FromTokioPostgresRow; use tokio_postgres::{NoTls, Row, Statement}; -use crate::{utils::internal_error, Fortune, World}; - #[derive(Debug)] +#[allow(dead_code)] pub enum PgError { Io(io::Error), Pg(tokio_postgres::Error), @@ -66,57 +71,26 @@ impl FromRequestParts for DatabaseClient { pub async fn fetch_world_by_id( client: &Client, - number: i32, + id: i32, select: &Statement, ) -> Result { - let row: Row = client.query_one(select, &[&number]).await.unwrap(); + let row: Row = client.query_one(select, &[&id]).await.unwrap(); Ok(World::from_row(row).unwrap()) } -pub async fn update_world( - client: &Client, - update: &Statement, - random_id: i32, - w_id: i32, -) -> Result { - let rows_modified: u64 = client.execute(update, &[&random_id, &w_id]).await.unwrap(); - - Ok(rows_modified) -} - pub async fn fetch_all_fortunes( client: Client, select: &Statement, ) -> Result, PgError> { - let rows: Vec = client.query(select, &[]).await.unwrap(); - - let mut fortunes: Vec = Vec::with_capacity(rows.capacity()); + let mut fortunes: Vec = Vec::new(); + let rows = client.query_raw::<_, _, &[i32; 0]>(select, &[]).await?; + pin!(rows); - for row in rows { - fortunes.push(Fortune::from_row(row).unwrap()); + while let Some(row) = rows.next().await.transpose()? { + fortunes + .push(Fortune::from_row(row).expect("could not convert row to fortune.")); } Ok(fortunes) } - -pub async fn prepare_fetch_all_fortunes_statement(client: &Client) -> Statement { - client - .prepare_cached("SELECT * FROM Fortune") - .await - .unwrap() -} - -pub async fn prepare_fetch_world_by_id_statement(client: &Client) -> Statement { - client - .prepare_cached("SELECT id, randomnumber FROM World WHERE id = $1") - .await - .unwrap() -} - -pub async fn prepare_update_world_by_id_statement(client: &Client) -> Statement { - client - .prepare_cached("UPDATE World SET randomnumber = $1 WHERE id = $2") - .await - .unwrap() -} diff --git a/frameworks/Rust/axum/src/pg_pool/mod.rs b/frameworks/Rust/axum/src/pg_pool/mod.rs new file mode 100644 index 00000000000..c51e02d23d3 --- /dev/null +++ b/frameworks/Rust/axum/src/pg_pool/mod.rs @@ -0,0 +1,2 @@ +pub mod database; +pub mod models; diff --git a/frameworks/Rust/axum/src/models_pg_pool.rs b/frameworks/Rust/axum/src/pg_pool/models.rs similarity index 100% rename from frameworks/Rust/axum/src/models_pg_pool.rs rename to frameworks/Rust/axum/src/pg_pool/models.rs diff --git a/frameworks/Rust/axum/src/server.rs b/frameworks/Rust/axum/src/server.rs index 29e165f6f5c..5e03a6aca88 100644 --- a/frameworks/Rust/axum/src/server.rs +++ b/frameworks/Rust/axum/src/server.rs @@ -1,37 +1,106 @@ use std::{ io, - net::{Ipv4Addr, SocketAddr}, + net::{Ipv4Addr, SocketAddr, TcpListener}, }; -use hyper::server::conn::AddrIncoming; -use tokio::net::{TcpListener, TcpSocket}; - -pub fn builder() -> hyper::server::Builder { - let addr = SocketAddr::from((Ipv4Addr::UNSPECIFIED, 8000)); - let listener = reuse_listener(addr).expect("couldn't bind to addr"); - let incoming = AddrIncoming::from_listener(listener).unwrap(); +use axum::{ + http::{header, HeaderValue}, + Router, +}; - println!("Started axum server at 8000"); +use hyper::body::Incoming; +use hyper::Request; +use hyper_util::rt::{TokioExecutor, TokioIo}; +use tower::Service; +use tower_http::set_header::SetResponseHeaderLayer; - axum::Server::builder(incoming) - .http1_only(true) - .tcp_nodelay(true) -} +use socket2::{Domain, Socket, Type}; -fn reuse_listener(addr: SocketAddr) -> io::Result { +/// Reuse an existing listener, ensuring that the socket `backlog`` +/// is set to enable a higher number of pending connections. +fn set_socket_options(addr: SocketAddr) -> io::Result { let socket = match addr { - SocketAddr::V4(_) => TcpSocket::new_v4()?, - SocketAddr::V6(_) => TcpSocket::new_v6()?, + SocketAddr::V4(_) => Socket::new(Domain::IPV4, Type::STREAM, None)?, + SocketAddr::V6(_) => Socket::new(Domain::IPV6, Type::STREAM, None)?, }; - #[cfg(unix)] - { - if let Err(e) = socket.set_reuseport(true) { - eprintln!("error setting SO_REUSEPORT: {e}"); - } - } + socket.set_reuse_port(true)?; + socket.set_reuse_address(true)?; + socket.set_nonblocking(true)?; + socket.set_nodelay(true)?; + socket.bind(&addr.into())?; + socket.listen(4096)?; + + let listener: TcpListener = socket.into(); + tokio::net::TcpListener::from_std(listener) +} + +/// Build an Axum server with consistent configuration, using the high-level API exposed +/// by Axum 0.7. This is intended for convenience and intentionally does not provide much +/// customisability. +#[allow(dead_code)] +pub async fn serve(app: Router<()>, port: Option) { + let port = port.unwrap_or(8000); + let addr = SocketAddr::from((Ipv4Addr::UNSPECIFIED, port)); + let listener = set_socket_options(addr).expect("couldn't bind to address"); + println!("started axum server on port {port}."); + + let server_header_value = HeaderValue::from_static("Axum"); + let app = app.layer(SetResponseHeaderLayer::overriding( + header::SERVER, + server_header_value, + )); - socket.set_reuseaddr(true)?; - socket.bind(addr)?; - socket.listen(1024) + axum::serve(listener, app.into_make_service()) + .await + .unwrap(); +} + +/// Build an Axum server using the lower-level Hyper APIs for more +/// configurability. This has a few optimisations, including: +/// * Serving HTTP/1 only. +/// * Disabling connection upgrades (websockets are not needed). +/// * Setting TCP_NODELAY on the input stream. +/// * Aggregating flushes to better support pipelined responses. +/// +/// See for more details: +/// * https://github.com/tokio-rs/axum/blob/1ac617a1b540e8523347f5ee889d65cad9a45ec4/examples/serve-with-hyper/src/main.rs +#[allow(dead_code)] +pub async fn serve_hyper(app: Router<()>, port: Option) { + let port = port.unwrap_or(8000); + let addr = SocketAddr::from((Ipv4Addr::UNSPECIFIED, port)); + let listener = set_socket_options(addr).expect("couldn't bind to address"); + println!("started axum server on port {port}."); + + let server_header_value = HeaderValue::from_static("Axum"); + let app = app.layer(SetResponseHeaderLayer::overriding( + header::SERVER, + server_header_value, + )); + + // Continuously accept new connections. + loop { + let (socket, _remote_addr) = listener.accept().await.unwrap(); + socket + .set_nodelay(true) + .expect("could not set TCP_NODELAY!"); + + let tower_service = app.clone(); + tokio::spawn(async move { + let socket = TokioIo::new(socket); + + let hyper_service = + hyper::service::service_fn(move |request: Request| { + tower_service.clone().call(request) + }); + + if (hyper_util::server::conn::auto::Builder::new(TokioExecutor::new()) + .http1() + .pipeline_flush(true) + .serve_connection(socket, hyper_service) + .await) + .is_err() + {} + }); + } } diff --git a/frameworks/Rust/axum/src/sqlx/database.rs b/frameworks/Rust/axum/src/sqlx/database.rs new file mode 100644 index 00000000000..1d824144696 --- /dev/null +++ b/frameworks/Rust/axum/src/sqlx/database.rs @@ -0,0 +1,36 @@ +use std::io; + +use sqlx::{postgres::PgPoolOptions, PgPool}; + +#[derive(Debug)] +#[allow(dead_code)] +pub enum PgError { + Io(io::Error), + Pg(sqlx::Error), +} + +impl From for PgError { + fn from(err: io::Error) -> Self { + PgError::Io(err) + } +} + +impl From for PgError { + fn from(err: sqlx::Error) -> Self { + PgError::Pg(err) + } +} + +pub async fn create_pool( + database_url: String, + max_pool_size: u32, + min_pool_size: u32, +) -> PgPool { + PgPoolOptions::new() + .max_connections(max_pool_size) + .min_connections(min_pool_size) + .test_before_acquire(false) + .connect(&database_url) + .await + .unwrap() +} diff --git a/frameworks/Rust/axum/src/sqlx/mod.rs b/frameworks/Rust/axum/src/sqlx/mod.rs new file mode 100644 index 00000000000..c51e02d23d3 --- /dev/null +++ b/frameworks/Rust/axum/src/sqlx/mod.rs @@ -0,0 +1,2 @@ +pub mod database; +pub mod models; diff --git a/frameworks/Rust/axum/src/models_sqlx.rs b/frameworks/Rust/axum/src/sqlx/models.rs similarity index 100% rename from frameworks/Rust/axum/src/models_sqlx.rs rename to frameworks/Rust/axum/src/sqlx/models.rs From a05b90e347cd3b8b29f1331c198e133b8600477d Mon Sep 17 00:00:00 2001 From: Ishtmeet Singh Date: Wed, 4 Sep 2024 01:22:48 +0530 Subject: [PATCH 099/204] Bumps version (#9241) --- frameworks/JavaScript/velocy/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frameworks/JavaScript/velocy/package.json b/frameworks/JavaScript/velocy/package.json index a51441b5c26..320f6058e7a 100644 --- a/frameworks/JavaScript/velocy/package.json +++ b/frameworks/JavaScript/velocy/package.json @@ -1,5 +1,5 @@ { "dependencies": { - "velocy": "0.0.13" + "velocy": "0.0.14" } } From 902efb7223f1243beada2f4d2d9bfcd4d6e9bd04 Mon Sep 17 00:00:00 2001 From: fakeshadow <24548779@qq.com> Date: Wed, 4 Sep 2024 03:53:11 +0800 Subject: [PATCH 100/204] [xitca-web] bug fix (#9243) * [xitca-web] bug fix * dep update. * template fix --- frameworks/Rust/xitca-web/Cargo.lock | 58 +++++++++---------- frameworks/Rust/xitca-web/Cargo.toml | 18 +++--- frameworks/Rust/xitca-web/src/db.rs | 4 +- .../Rust/xitca-web/templates/fortune.stpl | 2 +- 4 files changed, 41 insertions(+), 41 deletions(-) diff --git a/frameworks/Rust/xitca-web/Cargo.lock b/frameworks/Rust/xitca-web/Cargo.lock index 01bd80ec5e3..1f1f0e18a74 100644 --- a/frameworks/Rust/xitca-web/Cargo.lock +++ b/frameworks/Rust/xitca-web/Cargo.lock @@ -149,9 +149,9 @@ checksum = "8318a53db07bb3f8dca91a600466bdb3f2eaadeedfdbcf02e1accbad9271ba50" [[package]] name = "cc" -version = "1.1.13" +version = "1.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72db2f7947ecee9b03b510377e8bb9077afa27176fdbff55c51027e976fdcc48" +checksum = "57b6a275aa2903740dc87da01c62040406b8812552e97129a63ea8850a17c6e6" dependencies = [ "shlex", ] @@ -218,9 +218,9 @@ dependencies = [ [[package]] name = "diesel" -version = "2.2.2" +version = "2.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf97ee7261bb708fa3402fa9c17a54b70e90e3cb98afb3dc8999d5512cb03f94" +checksum = "65e13bab2796f412722112327f3e575601a3e9cdcbe426f0d30dbf43f3f5dc71" dependencies = [ "bitflags 2.6.0", "byteorder", @@ -232,9 +232,9 @@ dependencies = [ [[package]] name = "diesel_derives" -version = "2.2.2" +version = "2.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6ff2be1e7312c858b2ef974f5c7089833ae57b5311b334b30923af58e5718d8" +checksum = "e7f2c3de51e2ba6bf2a648285696137aaf0f5f487bcbea93972fe8a364e131a4" dependencies = [ "diesel_table_macro_syntax", "dsl_auto_type", @@ -291,9 +291,9 @@ checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7" [[package]] name = "filetime" -version = "0.2.24" +version = "0.2.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf401df4a4e3872c4fe8151134cf483738e74b67fc934d6532c882b3d24a4550" +checksum = "35c0522e981e68cbfa8c3f978441a5f34b30b96e146b33cd3359176b50fe8586" dependencies = [ "cfg-if", "libc", @@ -589,9 +589,9 @@ dependencies = [ [[package]] name = "object" -version = "0.36.3" +version = "0.36.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27b64972346851a39438c60b341ebc01bba47464ae329e55cf343eb93964efd9" +checksum = "084f1a5821ac4c651660a94a7153d27ac9d8a53736203f58b31945ded098070a" dependencies = [ "memchr", ] @@ -721,9 +721,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.36" +version = "1.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" +checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" dependencies = [ "proc-macro2", ] @@ -798,9 +798,9 @@ checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" [[package]] name = "sailfish" -version = "0.8.3" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "acd5f4680149b62b3478f6af08a8f1c37794bc1bc577e28874a4d0c70084d600" +checksum = "d4d5cd6d4f24f3ab107e949ab424738cf55b03deddce3b184c46985d7b1394ef" dependencies = [ "itoap", "ryu", @@ -810,9 +810,9 @@ dependencies = [ [[package]] name = "sailfish-compiler" -version = "0.8.3" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67087aca4a3886686a88cee6835089c53e6143a0b8c5be01e63e4fe2f6dfe7cb" +checksum = "7254ec7b3651f7f723a9073153f5dcddc1f2bf1bf8d1b23ac71c236ef6360d2b" dependencies = [ "filetime", "home", @@ -824,9 +824,9 @@ dependencies = [ [[package]] name = "sailfish-macros" -version = "0.8.3" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e47e31910c5f9230e99992568d05a5968fe4f42a635c3f912c993e9f66a619a5" +checksum = "00812289fe1891c191cc2d9db461352fc410619e07ec2bb748faaa06412619d0" dependencies = [ "proc-macro2", "sailfish-compiler", @@ -849,18 +849,18 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "serde" -version = "1.0.208" +version = "1.0.209" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cff085d2cb684faa248efb494c39b68e522822ac0de72ccf08109abde717cfb2" +checksum = "99fce0ffe7310761ca6bf9faf5115afbc19688edd00171d81b1bb1b116c63e09" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.208" +version = "1.0.209" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24008e81ff7613ed8e5ba0cfaf24e2c2f1e5b8a0495711e44fcd4882fca62bcf" +checksum = "a5831b979fd7b5439637af1752d535ff49f4860c0f341d1baeb6faf0f4242170" dependencies = [ "proc-macro2", "quote", @@ -869,9 +869,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.125" +version = "1.0.127" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83c8e735a073ccf5be70aa8066aa984eaf2fa000db6c8d0100ae605b366d31ed" +checksum = "8043c06d9f82bd7271361ed64f415fe5e12a77fdb52e573e7f06a516dea329ad" dependencies = [ "itoa", "memchr", @@ -987,9 +987,9 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "syn" -version = "2.0.75" +version = "2.0.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6af063034fc1935ede7be0122941bafa9bacb949334d090b77ca98b5817c7d9" +checksum = "9f35bcdf61fd8e7be6caf75f429fdca8beb3ed76584befb503b1569faee373ed" dependencies = [ "proc-macro2", "quote", @@ -1025,9 +1025,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.39.3" +version = "1.40.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9babc99b9923bfa4804bd74722ff02c0381021eafa4db9949217e3be8e84fff5" +checksum = "e2b070231665d27ad9ec9b8df639893f46727666c6767db40317fbe920a5d998" dependencies = [ "backtrace", "libc", @@ -1319,7 +1319,7 @@ dependencies = [ [[package]] name = "xitca-postgres" version = "0.1.0" -source = "git+https://github.com/HFQR/xitca-web.git?rev=f4e7bed#f4e7bedfb441897d1f26a6e4d8cbfada23953269" +source = "git+https://github.com/HFQR/xitca-web.git?rev=6870448#687044829f0e89bab3efafcf7fb53e53167ad32c" dependencies = [ "fallible-iterator", "percent-encoding", diff --git a/frameworks/Rust/xitca-web/Cargo.toml b/frameworks/Rust/xitca-web/Cargo.toml index e4614eb0bab..84eb12264b3 100644 --- a/frameworks/Rust/xitca-web/Cargo.toml +++ b/frameworks/Rust/xitca-web/Cargo.toml @@ -30,25 +30,25 @@ required-features = ["pg-orm", "template", "web-codegen"] [features] # pg optional -pg = ["xitca-postgres/single-thread"] +pg = ["dep:xitca-postgres"] # pg send/sync optional -pg-sync = ["xitca-postgres"] +pg-sync = ["dep:xitca-postgres"] # pg orm optional -pg-orm = ["diesel"] +pg-orm = ["dep:diesel"] # http router optional router = ["xitca-http/router"] # web optional -web = ["xitca-web"] +web = ["dep:xitca-web"] # web codegen optional web-codegen = ["xitca-web/codegen", "xitca-web/urlencoded"] # template optional -template = ["sailfish"] +template = ["dep:sailfish"] # io-uring optional io-uring = ["xitca-http/io-uring", "xitca-server/io-uring"] # axum optional -axum = ["dep:axum", "http-body", "tower", "tower-http", "xitca-web/tower-http-compat" ] +axum = ["dep:axum", "dep:http-body", "dep:tower", "dep:tower-http", "xitca-web/tower-http-compat" ] # unrealistic performance optimization -perf = ["mimalloc", "tokio/parking_lot"] +perf = ["dep:mimalloc", "tokio/parking_lot"] [dependencies] xitca-http = "0.6" @@ -71,7 +71,7 @@ xitca-postgres = { version = "0.1", optional = true } diesel = { version = "2", features = ["postgres", "r2d2"], optional = true } # template optional -sailfish = { version = "0.8", default-features = false, features = ["derive", "perf-inline"], optional = true } +sailfish = { version = "0.9", default-features = false, features = ["derive", "perf-inline"], optional = true } # axum optional axum = { version = "0.7", optional = true, default-features = false, features = ["json", "query"] } @@ -95,5 +95,5 @@ codegen-units = 1 panic = "abort" [patch.crates-io] -xitca-postgres = { git = "https://github.com/HFQR/xitca-web.git", rev = "f4e7bed" } +xitca-postgres = { git = "https://github.com/HFQR/xitca-web.git", rev = "6870448" } mio = { git = "https://github.com/fakeshadow/mio", rev = "9bae6012b7ecfc6083350785f71a5e8265358178" } diff --git a/frameworks/Rust/xitca-web/src/db.rs b/frameworks/Rust/xitca-web/src/db.rs index aa783e29dce..276eb93ec9e 100644 --- a/frameworks/Rust/xitca-web/src/db.rs +++ b/frameworks/Rust/xitca-web/src/db.rs @@ -100,7 +100,7 @@ impl Client { let mut res = { let (ref mut rng, ref mut buf) = *self.shared(); - let mut pipe = Pipeline::<_, false>::with_capacity_from_buf(len, buf); + let mut pipe = Pipeline::with_capacity_from_buf(len, buf); (0..num).try_for_each(|_| pipe.query_raw(&self.world, [rng.gen_id()]))?; @@ -128,7 +128,7 @@ impl Client { let mut res = { let (ref mut rng, ref mut buf) = *self.shared(); - let mut pipe = Pipeline::<_, false>::with_capacity_from_buf(len + 1, buf); + let mut pipe = Pipeline::with_capacity_from_buf(len + 1, buf); (0..num).try_for_each(|_| { let w_id = rng.gen_id(); diff --git a/frameworks/Rust/xitca-web/templates/fortune.stpl b/frameworks/Rust/xitca-web/templates/fortune.stpl index eb1abe6a4fa..28227945b4c 100644 --- a/frameworks/Rust/xitca-web/templates/fortune.stpl +++ b/frameworks/Rust/xitca-web/templates/fortune.stpl @@ -4,7 +4,7 @@ - <% for item in items { %><% } %> + <% for item in self.items { %><% } %>
idmessage
<%= item.id %><%= &*item.message %>
<%= item.id %><%= &*item.message %>
\ No newline at end of file From d62e690f2a9109f3dd8465704eafd35f933fc4b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=A5=BF=E4=B8=9C?= Date: Wed, 4 Sep 2024 03:53:44 +0800 Subject: [PATCH 101/204] Update Solon Jdk To 21 (#9245) * Update Solon Version To 2.9.1 * Update Solon Version To 2.9.1 * Update Solon Jdk To 21 * Update Solon Jdk To 21 * Update Solon Jdk To 21 * Update Solon Jdk To 21 * Update Solon Jdk To 21 --- frameworks/Java/solon/README.md | 8 +-- frameworks/Java/solon/pom.xml | 63 ++++--------------- frameworks/Java/solon/solon.dockerfile | 8 +-- .../src/main/java/{pmg => hello}/Main.java | 26 ++++---- .../controller/HelloController.java | 4 +- .../java/{pmg => hello}/model/Message.java | 2 +- 6 files changed, 35 insertions(+), 76 deletions(-) rename frameworks/Java/solon/src/main/java/{pmg => hello}/Main.java (87%) rename frameworks/Java/solon/src/main/java/{pmg => hello}/controller/HelloController.java (88%) rename frameworks/Java/solon/src/main/java/{pmg => hello}/model/Message.java (93%) diff --git a/frameworks/Java/solon/README.md b/frameworks/Java/solon/README.md index 0824b5effd9..f2370ab2305 100644 --- a/frameworks/Java/solon/README.md +++ b/frameworks/Java/solon/README.md @@ -4,13 +4,13 @@ This is the solon portion of a [benchmarking test suite](../) comparing a variety of web development platforms. ### JSON Encoding Test -* [JSON test source](src/main/java/pmg/Main.java) -* [Plaintext test source](src/main/java/pmg/Main.java) +* [JSON test source](src/main/java/hello/Main.java) +* [Plaintext test source](src/main/java/hello/Main.java) ## Versions -* [Java OpenJDK 1.8](http://openjdk.java.net/) -* [solon 2.0.0](https://github.com/noear/solon) +* [Java OpenJDK 21](http://openjdk.java.net/) +* [solon 2.9.1](https://github.com/noear/solon) ## Test URLs diff --git a/frameworks/Java/solon/pom.xml b/frameworks/Java/solon/pom.xml index df69e436229..a9568927908 100644 --- a/frameworks/Java/solon/pom.xml +++ b/frameworks/Java/solon/pom.xml @@ -2,15 +2,19 @@ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 - org.noear.solon - solon-benchmark + + org.noear + solon-parent + 2.9.1 + + + hello + hello-solon 1.0 jar - UTF-8 - 11 - 2.9.1 + 21 @@ -19,6 +23,7 @@ solon.boot.smarthttp ${solon.version} + org.noear solon.serialization.snack3 @@ -26,66 +31,20 @@ - - - central - Central Repository - https://repo.maven.apache.org/maven2 - - - sonatype-nexus-snapshots - Sonatype Nexus Snapshots - https://oss.sonatype.org/content/repositories/snapshots - - - - - - central - Central Repository - https://repo.maven.apache.org/maven2 - - - sonatype-nexus-snapshots - Sonatype Nexus Snapshots - https://oss.sonatype.org/content/repositories/snapshots - - false - - - true - - - - ${project.artifactId} - - org.apache.maven.plugins - maven-compiler-plugin - 3.11.0 - - -parameters - ${java.vertsion} - ${java.vertsion} - UTF-8 - false - - - org.apache.maven.plugins maven-assembly-plugin - 3.6.0 jar-with-dependencies - pmg.Main + hello.Main diff --git a/frameworks/Java/solon/solon.dockerfile b/frameworks/Java/solon/solon.dockerfile index 21d7f50d8a8..c387938661c 100644 --- a/frameworks/Java/solon/solon.dockerfile +++ b/frameworks/Java/solon/solon.dockerfile @@ -1,13 +1,13 @@ -FROM maven:3.6.1-jdk-11-slim as maven +FROM maven:3.9.7-amazoncorretto-21 as maven WORKDIR /solon COPY pom.xml pom.xml COPY src src RUN mvn compile assembly:single -q -FROM openjdk:11.0.3-jdk-slim +FROM openjdk:21-jdk-slim WORKDIR /solon -COPY --from=maven /solon/target/solon-benchmark-jar-with-dependencies.jar app.jar +COPY --from=maven /solon/target/hello-solon.jar app.jar EXPOSE 8080 -CMD ["java", "-server", "-XX:+UseNUMA", "-XX:+UseParallelGC", "-XX:+AggressiveOpts", "-cp", "app.jar", "pmg.Main"] +CMD ["java", "-server", "-cp", "app.jar", "hello.Main"] \ No newline at end of file diff --git a/frameworks/Java/solon/src/main/java/pmg/Main.java b/frameworks/Java/solon/src/main/java/hello/Main.java similarity index 87% rename from frameworks/Java/solon/src/main/java/pmg/Main.java rename to frameworks/Java/solon/src/main/java/hello/Main.java index b4b7b651797..0746f86be45 100644 --- a/frameworks/Java/solon/src/main/java/pmg/Main.java +++ b/frameworks/Java/solon/src/main/java/hello/Main.java @@ -1,13 +1,13 @@ -package pmg; - -import org.noear.solon.Solon; - -/** - * @author pmg1991 - * @version V1.0 - */ -public class Main { - public static void main(String[] args) { - Solon.start(Main.class, args); - } -} +package hello; + +import org.noear.solon.Solon; + +/** + * @author pmg1991 + * @version V1.0 + */ +public class Main { + public static void main(String[] args) { + Solon.start(Main.class, args); + } +} diff --git a/frameworks/Java/solon/src/main/java/pmg/controller/HelloController.java b/frameworks/Java/solon/src/main/java/hello/controller/HelloController.java similarity index 88% rename from frameworks/Java/solon/src/main/java/pmg/controller/HelloController.java rename to frameworks/Java/solon/src/main/java/hello/controller/HelloController.java index fe9a1b43e3a..77049043e97 100644 --- a/frameworks/Java/solon/src/main/java/pmg/controller/HelloController.java +++ b/frameworks/Java/solon/src/main/java/hello/controller/HelloController.java @@ -1,9 +1,9 @@ -package pmg.controller; +package hello.controller; import org.noear.solon.annotation.Controller; import org.noear.solon.annotation.Get; import org.noear.solon.annotation.Mapping; -import pmg.model.Message; +import hello.model.Message; /** * @author noear diff --git a/frameworks/Java/solon/src/main/java/pmg/model/Message.java b/frameworks/Java/solon/src/main/java/hello/model/Message.java similarity index 93% rename from frameworks/Java/solon/src/main/java/pmg/model/Message.java rename to frameworks/Java/solon/src/main/java/hello/model/Message.java index f88b9b1a8d4..1df5276ca8d 100644 --- a/frameworks/Java/solon/src/main/java/pmg/model/Message.java +++ b/frameworks/Java/solon/src/main/java/hello/model/Message.java @@ -1,4 +1,4 @@ -package pmg.model; +package hello.model; /** * @author pmg1991 From 9ae18ac38774bb48ea9a6eacd0454a79d1a5c9cc Mon Sep 17 00:00:00 2001 From: Vladimir Shchur Date: Tue, 3 Sep 2024 22:54:16 +0300 Subject: [PATCH 102/204] [F#/Oxpecker] Improvements for json and fortunes benchmarks (#9246) * [F#/Oxpecker] Improved fortunes rendering * [F#/Oxpecker] Use SpanJson for json benchmark --- frameworks/FSharp/oxpecker/README.md | 2 +- frameworks/FSharp/oxpecker/src/App/App.fsproj | 2 ++ frameworks/FSharp/oxpecker/src/App/Program.fs | 22 +++++++++---------- 3 files changed, 14 insertions(+), 12 deletions(-) diff --git a/frameworks/FSharp/oxpecker/README.md b/frameworks/FSharp/oxpecker/README.md index 3d8a00a248a..a35cbf08522 100644 --- a/frameworks/FSharp/oxpecker/README.md +++ b/frameworks/FSharp/oxpecker/README.md @@ -19,5 +19,5 @@ This includes tests for plaintext, json, fortunes, single query, mutliple querie * [Oxpecker](https://github.com/Lanayx/Oxpecker) * [Npgsql](https://github.com/npgsql/npgsql) -* [System.Text.Json](https://github.com/dotnet/runtime/tree/main/src/libraries/System.Text.Json) +* [SpanJson](https://github.com/Tornhoof/SpanJson) * ASP.NET Core \ No newline at end of file diff --git a/frameworks/FSharp/oxpecker/src/App/App.fsproj b/frameworks/FSharp/oxpecker/src/App/App.fsproj index 35df8d5c493..e9aa702a5a1 100644 --- a/frameworks/FSharp/oxpecker/src/App/App.fsproj +++ b/frameworks/FSharp/oxpecker/src/App/App.fsproj @@ -15,6 +15,8 @@ + + \ No newline at end of file diff --git a/frameworks/FSharp/oxpecker/src/App/Program.fs b/frameworks/FSharp/oxpecker/src/App/Program.fs index ea6bc66b911..895c54c9693 100644 --- a/frameworks/FSharp/oxpecker/src/App/Program.fs +++ b/frameworks/FSharp/oxpecker/src/App/Program.fs @@ -2,6 +2,7 @@ namespace App open System open Oxpecker +open System.Runtime.InteropServices [] module HtmlViews = @@ -26,21 +27,20 @@ module HtmlViews = ) |> RenderHelpers.prerender let fortunes (fortunesData: ResizeArray) = - RenderHelpers.combine head tail ( - __() { - for fortune in fortunesData do - tr() { - td() { raw <| string fortune.id } - td() { fortune.message } - } + let fragment = __() + for fortune in CollectionsMarshal.AsSpan fortunesData do + tr() { + td() { raw <| string fortune.id } + td() { fortune.message } } - ) + |> fragment.AddChild + RenderHelpers.combine head tail fragment [] module HttpHandlers = open System.Text open Microsoft.AspNetCore.Http - open System.Text.Json + open SpanJson let private extra = { @@ -98,9 +98,9 @@ module HttpHandlers = ctx.WriteBytes(result) let jsonSimple value : EndpointHandler = - let options = JsonSerializerOptions(JsonSerializerDefaults.Web) fun ctx -> - ctx.Response.WriteAsJsonAsync(value, options) + ctx.SetContentType("application/json") + JsonSerializer.Generic.Utf8.SerializeAsync<_>(value, stream = ctx.Response.Body).AsTask() let endpoints = [| From f7a663eaf6b46d90f0b2541334cb1da72e2cd259 Mon Sep 17 00:00:00 2001 From: kanarus Date: Wed, 4 Sep 2024 04:54:40 +0900 Subject: [PATCH 103/204] bunp ohkami to v0.20, deps & refactor some (#9247) --- frameworks/Rust/ohkami/Cargo.lock | 565 ++++++++++++----------- frameworks/Rust/ohkami/Cargo.toml | 19 +- frameworks/Rust/ohkami/ohkami.dockerfile | 2 +- frameworks/Rust/ohkami/src/fangs.rs | 39 -- frameworks/Rust/ohkami/src/main.rs | 36 +- frameworks/Rust/ohkami/src/models.rs | 9 +- frameworks/Rust/ohkami/src/postgres.rs | 29 +- 7 files changed, 363 insertions(+), 336 deletions(-) diff --git a/frameworks/Rust/ohkami/Cargo.lock b/frameworks/Rust/ohkami/Cargo.lock index 95d46009a5b..e379d121817 100644 --- a/frameworks/Rust/ohkami/Cargo.lock +++ b/frameworks/Rust/ohkami/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "addr2line" -version = "0.21.0" +version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" +checksum = "6e4503c46a5c0c7844e948c9a4d6acd9f50cccb4de1c48eb9e291ea17470c678" dependencies = [ "gimli", ] @@ -24,7 +24,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" dependencies = [ "cfg-if", - "getrandom", "once_cell", "version_check", "zerocopy", @@ -66,15 +65,15 @@ dependencies = [ [[package]] name = "autocfg" -version = "1.2.0" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1fdabc7756949593fe60f30ec81974b613357de856987752631dea1e3394c80" +checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" [[package]] name = "backtrace" -version = "0.3.71" +version = "0.3.73" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26b05800d2e817c8b3b4b54abd461726265fa9789ae34330622f2db9ee696f9d" +checksum = "5cc23269a4f8976d0a4d2e7109211a419fe30e8d88d677cd60b6bc79c5732e0a" dependencies = [ "addr2line", "cc", @@ -87,9 +86,9 @@ dependencies = [ [[package]] name = "base64" -version = "0.21.7" +version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" [[package]] name = "base64ct" @@ -105,9 +104,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.5.0" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" +checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" dependencies = [ "serde", ] @@ -123,9 +122,9 @@ dependencies = [ [[package]] name = "byte_reader" -version = "3.0.0" +version = "3.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fac67f5455e694831246ed9a2d62c98dbb7586281dcfaba6621888ac9b576df" +checksum = "3aad623c0c9416ec94524edd23af3f3e2fd16d1ec7d41c940084c05f77e35c96" [[package]] name = "byteorder" @@ -135,15 +134,18 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.6.0" +version = "1.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9" +checksum = "8318a53db07bb3f8dca91a600466bdb3f2eaadeedfdbcf02e1accbad9271ba50" [[package]] name = "cc" -version = "1.0.95" +version = "1.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d32a725bc159af97c3e629873bb9f88fb8cf8a4867175f76dc987815ea07c83b" +checksum = "57b6a275aa2903740dc87da01c62040406b8812552e97129a63ea8850a17c6e6" +dependencies = [ + "shlex", +] [[package]] name = "cfg-if" @@ -151,6 +153,15 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "concurrent-queue" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" +dependencies = [ + "crossbeam-utils", +] + [[package]] name = "const-oid" version = "0.9.6" @@ -175,15 +186,15 @@ dependencies = [ [[package]] name = "core-foundation-sys" -version = "0.8.6" +version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" [[package]] name = "cpufeatures" -version = "0.2.12" +version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" +checksum = "51e852e6dc9a5bed1fae92dd2375037bf2b768725bf3be87811edee3249d09ad" dependencies = [ "libc", ] @@ -214,9 +225,9 @@ dependencies = [ [[package]] name = "crossbeam-utils" -version = "0.8.19" +version = "0.8.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345" +checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" [[package]] name = "crypto-common" @@ -241,15 +252,15 @@ dependencies = [ [[package]] name = "derive_more" -version = "0.99.17" +version = "0.99.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321" +checksum = "5f33878137e4dafd7fa914ad4e259e18a4e8e532b9617a2d0150262bf53abfce" dependencies = [ "convert_case", "proc-macro2", "quote", "rustc_version", - "syn 1.0.109", + "syn 2.0.77", ] [[package]] @@ -278,9 +289,9 @@ checksum = "dcbb2bf8e87535c23f7a8a321e364ce21462d0ff10cb6407820e8e96dfff6653" [[package]] name = "either" -version = "1.11.0" +version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a47c1c47d2f5964e29c61246e81db715514cd532db6b5116a25ea3c03d6780a2" +checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" dependencies = [ "serde", ] @@ -293,9 +304,9 @@ checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] name = "errno" -version = "0.3.8" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" +checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" dependencies = [ "libc", "windows-sys 0.52.0", @@ -314,21 +325,20 @@ dependencies = [ [[package]] name = "event-listener" -version = "2.5.3" +version = "5.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" +checksum = "6032be9bd27023a771701cc49f9f053c751055f71efb2e0ae5c15809093675ba" +dependencies = [ + "concurrent-queue", + "parking", + "pin-project-lite", +] [[package]] name = "fastrand" -version = "2.0.2" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "658bd65b1cf4c852a3cc96f18a8ce7b5640f6b703f905c7d74532294c2a63984" - -[[package]] -name = "finl_unicode" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fcfdc7a0362c9f4444381a9e697c79d435fe65b52a37466fc2c1184cee9edc6" +checksum = "e8c02a5121d4ea3eb16a80748c74f5549a5665e4c21333c6098f283870fbdea6" [[package]] name = "flume" @@ -338,7 +348,7 @@ checksum = "55ac459de2512911e4b674ce33cf20befaba382d05b62b008afc1c8b57cbf181" dependencies = [ "futures-core", "futures-sink", - "spin 0.9.8", + "spin", ] [[package]] @@ -417,7 +427,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.77", ] [[package]] @@ -461,9 +471,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.14" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94b22e06ecb0110981051723910cbf0b5f5e09a2062dd7663334ee79a9d1286c" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" dependencies = [ "cfg-if", "libc", @@ -472,15 +482,15 @@ dependencies = [ [[package]] name = "gimli" -version = "0.28.1" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" +checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd" [[package]] name = "hashbrown" -version = "0.14.3" +version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" dependencies = [ "ahash", "allocator-api2", @@ -488,21 +498,18 @@ dependencies = [ [[package]] name = "hashlink" -version = "0.8.4" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8094feaf31ff591f651a2664fb9cfd92bba7a60ce3197265e9482ebe753c8f7" +checksum = "6ba4ff7128dee98c7dc9794b6a411377e1404dba1c97deb8d1a55297bd25d8af" dependencies = [ "hashbrown", ] [[package]] name = "heck" -version = "0.4.1" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" -dependencies = [ - "unicode-segmentation", -] +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" [[package]] name = "hermit-abi" @@ -555,23 +562,14 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.2.6" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" +checksum = "68b900aa2f7301e21c36462b170ee99994de34dff39a4a6a528e80e7376d07e5" dependencies = [ "equivalent", "hashbrown", ] -[[package]] -name = "itertools" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" -dependencies = [ - "either", -] - [[package]] name = "itoa" version = "1.0.11" @@ -580,18 +578,18 @@ checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" [[package]] name = "lazy_static" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" dependencies = [ - "spin 0.5.2", + "spin", ] [[package]] name = "libc" -version = "0.2.153" +version = "0.2.158" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" +checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439" [[package]] name = "libm" @@ -601,9 +599,9 @@ checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" [[package]] name = "libsqlite3-sys" -version = "0.27.0" +version = "0.30.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf4e226dcd58b4be396f7bd3c20da8fdee2911400705297ba7d2d7cc2c30f716" +checksum = "2e99fb7a497b1e3339bc746195567ed8d3e24945ecd636e3619d20b9de9e9149" dependencies = [ "cc", "pkg-config", @@ -612,15 +610,15 @@ dependencies = [ [[package]] name = "linux-raw-sys" -version = "0.4.13" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c" +checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" [[package]] name = "lock_api" -version = "0.4.11" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45" +checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" dependencies = [ "autocfg", "scopeguard", @@ -628,9 +626,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.21" +version = "0.4.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" +checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" [[package]] name = "md-5" @@ -644,9 +642,9 @@ dependencies = [ [[package]] name = "memchr" -version = "2.7.2" +version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "minimal-lexical" @@ -656,31 +654,31 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] name = "miniz_oxide" -version = "0.7.2" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d811f3e15f28568be3407c8e7fdb6514c1cda3cb30683f15b6a1a1dc4ea14a7" +checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08" dependencies = [ "adler", ] [[package]] name = "mio" -version = "0.8.11" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" +checksum = "80e04d1dcff3aae0704555fe5fee3bcfaf3d1fdf8a7e521d5b9d2b42acb52cec" dependencies = [ + "hermit-abi", "libc", "wasi", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] name = "native-tls" -version = "0.2.11" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07226173c32f2926027b63cce4bcd8076c3552846cbe7925f3aaffeac0a3b92e" +checksum = "a8614eb2c83d59d1c8cc974dd3f920198647674a0a035e1af1fa58707e317466" dependencies = [ - "lazy_static", "libc", "log", "openssl", @@ -730,9 +728,9 @@ dependencies = [ [[package]] name = "num-iter" -version = "0.1.44" +version = "0.1.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d869c01cc0c455284163fd0092f1f93835385ccab5a98a0dcc497b2f8bf055a9" +checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" dependencies = [ "autocfg", "num-integer", @@ -741,38 +739,28 @@ dependencies = [ [[package]] name = "num-traits" -version = "0.2.18" +version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da0df0e5185db44f69b44f26786fe401b6c293d1907744beaa7fa62b2e5a517a" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ "autocfg", "libm", ] -[[package]] -name = "num_cpus" -version = "1.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" -dependencies = [ - "hermit-abi", - "libc", -] - [[package]] name = "object" -version = "0.32.2" +version = "0.36.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441" +checksum = "084f1a5821ac4c651660a94a7153d27ac9d8a53736203f58b31945ded098070a" dependencies = [ "memchr", ] [[package]] name = "ohkami" -version = "0.19.0" +version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e598d3d323527b920e159d55da2754067a5edfbc0678d60b3886fc379f4637f2" +checksum = "aa5507d0f2230d8fbbec9163207da1219ac513441269465a8d532e0bf5018411" dependencies = [ "byte_reader", "hmac", @@ -787,7 +775,7 @@ dependencies = [ [[package]] name = "ohkami_framework_benchmarks" -version = "0.19.0" +version = "0.20.0" dependencies = [ "futures-util", "ohkami", @@ -799,9 +787,9 @@ dependencies = [ [[package]] name = "ohkami_lib" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05fdeee00f86ee850c63a15068f2c2a3aeb6d707d4936f2261ec0e70ff48704b" +checksum = "889b290a5ca6f0e2d1b1bae72d0ec1fb768d84cf246c532e6f7c65ff962e65e3" dependencies = [ "byte_reader", "percent-encoding", @@ -810,9 +798,9 @@ dependencies = [ [[package]] name = "ohkami_macros" -version = "0.7.4" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5fa46d8805dede76dce71f8725d48d655f74e2c702824f7a785257d1cc4dd1b" +checksum = "8a231d9afdadeab9fc5c850093377c65ecd30512692de0efec51f708dff5be12" dependencies = [ "proc-macro2", "quote", @@ -827,11 +815,11 @@ checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" [[package]] name = "openssl" -version = "0.10.64" +version = "0.10.66" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95a0481286a310808298130d22dd1fef0fa571e05a8f44ec801801e84b216b1f" +checksum = "9529f4786b70a3e8c61e11179af17ab6188ad8d0ded78c5529441ed39d4bd9c1" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.6.0", "cfg-if", "foreign-types", "libc", @@ -848,7 +836,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.77", ] [[package]] @@ -859,9 +847,9 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" [[package]] name = "openssl-sys" -version = "0.9.102" +version = "0.9.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c597637d56fbc83893a35eb0dd04b2b8e7a50c91e64e9493e398b5df4fb45fa2" +checksum = "7f9e8deee91df40a943c71b917e5874b951d32a802526c85721ce3b776c929d6" dependencies = [ "cc", "libc", @@ -869,11 +857,17 @@ dependencies = [ "vcpkg", ] +[[package]] +name = "parking" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb813b8af86854136c6922af0598d719255ecb2179515e6e7730d468f05c9cae" + [[package]] name = "parking_lot" -version = "0.12.1" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" +checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" dependencies = [ "lock_api", "parking_lot_core", @@ -881,22 +875,22 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.9" +version = "0.9.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e" +checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" dependencies = [ "cfg-if", "libc", - "redox_syscall", + "redox_syscall 0.5.3", "smallvec", - "windows-targets 0.48.5", + "windows-targets 0.52.6", ] [[package]] name = "paste" -version = "1.0.14" +version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" [[package]] name = "pem-rfc7468" @@ -954,9 +948,12 @@ checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" [[package]] name = "ppv-lite86" -version = "0.2.17" +version = "0.2.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" +checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" +dependencies = [ + "zerocopy", +] [[package]] name = "prettyplease" @@ -970,18 +967,18 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.81" +version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d1597b0c024618f09a9c3b8655b7e430397a36d23fdafec26d6965e9eec3eba" +checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.36" +version = "1.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" +checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" dependencies = [ "proc-macro2", ] @@ -1025,11 +1022,20 @@ dependencies = [ "bitflags 1.3.2", ] +[[package]] +name = "redox_syscall" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a908a6e00f1fdd0dfd9c0eb08ce85126f6d8bbda50017e74bc4a4b7d4a926a4" +dependencies = [ + "bitflags 2.6.0", +] + [[package]] name = "regex" -version = "1.10.4" +version = "1.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c117dbdfde9c8308975b6a18d71f3f385c89461f7b3fb054288ecf2a2058ba4c" +checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619" dependencies = [ "aho-corasick", "memchr", @@ -1039,9 +1045,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.6" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea" +checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" dependencies = [ "aho-corasick", "memchr", @@ -1050,9 +1056,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.8.3" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56" +checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" [[package]] name = "rsa" @@ -1076,32 +1082,32 @@ dependencies = [ [[package]] name = "rustc-demangle" -version = "0.1.23" +version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" +checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" [[package]] name = "rustc-hash" -version = "1.1.0" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" +checksum = "583034fd73374156e66797ed8e5b0d5690409c9226b22d87cb7f19821c05d152" [[package]] name = "rustc_version" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" dependencies = [ "semver", ] [[package]] name = "rustix" -version = "0.38.34" +version = "0.38.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" +checksum = "a85d50532239da68e9addb745ba38ff4612a242c1c7ceea689c4bc7c2f43c36f" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.6.0", "errno", "libc", "linux-raw-sys", @@ -1110,9 +1116,9 @@ dependencies = [ [[package]] name = "ryu" -version = "1.0.17" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1" +checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" [[package]] name = "schannel" @@ -1131,11 +1137,11 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "security-framework" -version = "2.10.0" +version = "2.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "770452e37cad93e0a50d5abc3990d2bc351c36d0328f86cefec2f2fb206eaef6" +checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.6.0", "core-foundation", "core-foundation-sys", "libc", @@ -1144,9 +1150,9 @@ dependencies = [ [[package]] name = "security-framework-sys" -version = "2.10.0" +version = "2.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41f3cc463c0ef97e11c3461a9d3787412d30e8e7eb907c79180c4a57bf7c04ef" +checksum = "75da29fe9b9b08fe9d6b22b5b4bcbc75d8db3aa31e639aa56bb62e9d46bfceaf" dependencies = [ "core-foundation-sys", "libc", @@ -1154,36 +1160,49 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.22" +version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92d43fe69e652f3df9bdc2b85b2854a0825b86e4fb76bc44d945137d053639ca" +checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" [[package]] name = "serde" -version = "1.0.198" +version = "1.0.209" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9846a40c979031340571da2545a4e5b7c4163bdae79b301d5f86d03979451fcc" +checksum = "99fce0ffe7310761ca6bf9faf5115afbc19688edd00171d81b1bb1b116c63e09" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.198" +version = "1.0.209" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e88edab869b01783ba905e7d0153f9fc1a6505a96e4ad3018011eedb838566d9" +checksum = "a5831b979fd7b5439637af1752d535ff49f4860c0f341d1baeb6faf0f4242170" dependencies = [ "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.77", ] [[package]] name = "serde_json" -version = "1.0.116" +version = "1.0.127" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8043c06d9f82bd7271361ed64f415fe5e12a77fdb52e573e7f06a516dea329ad" +dependencies = [ + "itoa", + "memchr", + "ryu", + "serde", +] + +[[package]] +name = "serde_urlencoded" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e17db7126d17feb94eb3fad46bf1a96b034e8aacbc2e775fe81505f8b0b2813" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" dependencies = [ + "form_urlencoded", "itoa", "ryu", "serde", @@ -1211,6 +1230,12 @@ dependencies = [ "digest", ] +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + [[package]] name = "signal-hook-registry" version = "1.4.2" @@ -1244,23 +1269,20 @@ name = "smallvec" version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" +dependencies = [ + "serde", +] [[package]] name = "socket2" -version = "0.5.6" +version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05ffd9c0a93b7543e062e759284fcf5f5e3b098501104bfbdde4d404db792871" +checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c" dependencies = [ "libc", "windows-sys 0.52.0", ] -[[package]] -name = "spin" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" - [[package]] name = "spin" version = "0.9.8" @@ -1282,20 +1304,19 @@ dependencies = [ [[package]] name = "sqlformat" -version = "0.2.3" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce81b7bd7c4493975347ef60d8c7e8b742d4694f4c49f93e0a12ea263938176c" +checksum = "f895e3734318cc55f1fe66258926c9b910c124d47520339efecbb6c59cec7c1f" dependencies = [ - "itertools", "nom", "unicode_categories", ] [[package]] name = "sqlx" -version = "0.7.4" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9a2ccff1a000a5a59cd33da541d9f2fdcd9e6e8229cc200565942bff36d0aaa" +checksum = "fcfa89bea9500db4a0d038513d7a060566bfc51d46d1c014847049a45cce85e8" dependencies = [ "sqlx-core", "sqlx-macros", @@ -1306,11 +1327,10 @@ dependencies = [ [[package]] name = "sqlx-core" -version = "0.7.4" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24ba59a9342a3d9bab6c56c118be528b27c9b60e490080e9711a04dccac83ef6" +checksum = "d06e2f2bd861719b1f3f0c7dbe1d80c30bf59e76cf019f07d9014ed7eefb8e08" dependencies = [ - "ahash", "atoi", "byteorder", "bytes", @@ -1323,6 +1343,7 @@ dependencies = [ "futures-intrusive", "futures-io", "futures-util", + "hashbrown", "hashlink", "hex", "indexmap", @@ -1346,22 +1367,22 @@ dependencies = [ [[package]] name = "sqlx-macros" -version = "0.7.4" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ea40e2345eb2faa9e1e5e326db8c34711317d2b5e08d0d5741619048a803127" +checksum = "2f998a9defdbd48ed005a89362bd40dd2117502f15294f61c8d47034107dbbdc" dependencies = [ "proc-macro2", "quote", "sqlx-core", "sqlx-macros-core", - "syn 1.0.109", + "syn 2.0.77", ] [[package]] name = "sqlx-macros-core" -version = "0.7.4" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5833ef53aaa16d860e92123292f1f6a3d53c34ba8b1969f152ef1a7bb803f3c8" +checksum = "3d100558134176a2629d46cec0c8891ba0be8910f7896abfdb75ef4ab6f4e7ce" dependencies = [ "dotenvy", "either", @@ -1377,7 +1398,7 @@ dependencies = [ "sqlx-mysql", "sqlx-postgres", "sqlx-sqlite", - "syn 1.0.109", + "syn 2.0.77", "tempfile", "tokio", "url", @@ -1385,13 +1406,13 @@ dependencies = [ [[package]] name = "sqlx-mysql" -version = "0.7.4" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ed31390216d20e538e447a7a9b959e06ed9fc51c37b514b46eb758016ecd418" +checksum = "936cac0ab331b14cb3921c62156d913e4c15b74fb6ec0f3146bd4ef6e4fb3c12" dependencies = [ "atoi", "base64", - "bitflags 2.5.0", + "bitflags 2.6.0", "byteorder", "bytes", "crc", @@ -1427,13 +1448,13 @@ dependencies = [ [[package]] name = "sqlx-postgres" -version = "0.7.4" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c824eb80b894f926f89a0b9da0c7f435d27cdd35b8c655b114e58223918577e" +checksum = "9734dbce698c67ecf67c442f768a5e90a49b2a4d61a9f1d59f73874bd4cf0710" dependencies = [ "atoi", "base64", - "bitflags 2.5.0", + "bitflags 2.6.0", "byteorder", "crc", "dotenvy", @@ -1465,9 +1486,9 @@ dependencies = [ [[package]] name = "sqlx-sqlite" -version = "0.7.4" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b244ef0a8414da0bed4bb1910426e890b19e5e9bccc27ada6b797d05c55ae0aa" +checksum = "a75b419c3c1b1697833dd927bdc4c6545a620bc1bbafabd44e1efbe9afcd337e" dependencies = [ "atoi", "flume", @@ -1480,28 +1501,28 @@ dependencies = [ "log", "percent-encoding", "serde", + "serde_urlencoded", "sqlx-core", "tracing", "url", - "urlencoding", ] [[package]] name = "stringprep" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb41d74e231a107a1b4ee36bd1214b11285b77768d2e3824aedafa988fd36ee6" +checksum = "7b4df3d392d81bd458a8a621b8bffbd2302a12ffe288a9d931670948749463b1" dependencies = [ - "finl_unicode", "unicode-bidi", "unicode-normalization", + "unicode-properties", ] [[package]] name = "subtle" -version = "2.5.0" +version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "syn" @@ -1516,9 +1537,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.60" +version = "2.0.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "909518bc7b1c9b779f1bbf07f2929d35af9f0f37e47c6e9ef7f9dddc1e1821f3" +checksum = "9f35bcdf61fd8e7be6caf75f429fdca8beb3ed76584befb503b1569faee373ed" dependencies = [ "proc-macro2", "quote", @@ -1527,41 +1548,42 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.10.1" +version = "3.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1" +checksum = "04cbcdd0c794ebb0d4cf35e88edd2f7d2c4c3e9a5a6dab322839b321c6a87a64" dependencies = [ "cfg-if", "fastrand", + "once_cell", "rustix", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] name = "thiserror" -version = "1.0.59" +version = "1.0.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0126ad08bff79f29fc3ae6a55cc72352056dfff61e3ff8bb7129476d44b23aa" +checksum = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.59" +version = "1.0.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1cd413b5d558b4c5bf3680e324a6fa5014e7b7c067a51e69dbdf47eb7148b66" +checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261" dependencies = [ "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.77", ] [[package]] name = "tinyvec" -version = "1.6.0" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +checksum = "445e881f4f6d382d5f27c034e25eb92edd7c784ceab92a0937db7f2e9471b938" dependencies = [ "tinyvec_macros", ] @@ -1574,32 +1596,31 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.38.0" +version = "1.40.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba4f4a02a7a80d6f274636f0aa95c7e383b912d41fe721a31f29e29698585a4a" +checksum = "e2b070231665d27ad9ec9b8df639893f46727666c6767db40317fbe920a5d998" dependencies = [ "backtrace", "bytes", "libc", "mio", - "num_cpus", "parking_lot", "pin-project-lite", "signal-hook-registry", "socket2", "tokio-macros", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] name = "tokio-macros" -version = "2.3.0" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f5ae998a069d4b5aba8ee9dad856af7d520c3699e6159b185c2acd48155d39a" +checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" dependencies = [ "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.77", ] [[package]] @@ -1642,7 +1663,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.77", ] [[package]] @@ -1682,22 +1703,22 @@ dependencies = [ ] [[package]] -name = "unicode-segmentation" -version = "1.11.0" +name = "unicode-properties" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202" +checksum = "52ea75f83c0137a9b98608359a5f1af8144876eb67bcb1ce837368e906a9f524" [[package]] name = "unicode-width" -version = "0.1.11" +version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85" +checksum = "0336d538f7abc86d282a4189614dfaa90810dfc2c6f6427eaf88e16311dd225d" [[package]] name = "unicode-xid" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" +checksum = "229730647fbc343e3a80e463c1db7f78f3855d3f3739bee0dda773c9a037c90a" [[package]] name = "unicode_categories" @@ -1707,21 +1728,15 @@ checksum = "39ec24b3121d976906ece63c9daad25b85969647682eee313cb5779fdd69e14e" [[package]] name = "url" -version = "2.5.0" +version = "2.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633" +checksum = "22784dbdf76fdde8af1aeda5622b546b422b6fc585325248a2bf9f5e41e94d6c" dependencies = [ "form_urlencoded", "idna", "percent-encoding", ] -[[package]] -name = "urlencoding" -version = "2.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da" - [[package]] name = "v_eval" version = "0.6.0" @@ -1746,9 +1761,9 @@ checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" [[package]] name = "version_check" -version = "0.9.4" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" [[package]] name = "wasi" @@ -1768,7 +1783,7 @@ version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a44ab49fad634e88f55bf8f9bb3abd2f27d7204172a112c7c9987e01c1c94ea9" dependencies = [ - "redox_syscall", + "redox_syscall 0.4.1", "wasite", ] @@ -1809,7 +1824,16 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets 0.52.5", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets 0.52.6", ] [[package]] @@ -1829,18 +1853,18 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ - "windows_aarch64_gnullvm 0.52.5", - "windows_aarch64_msvc 0.52.5", - "windows_i686_gnu 0.52.5", + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", "windows_i686_gnullvm", - "windows_i686_msvc 0.52.5", - "windows_x86_64_gnu 0.52.5", - "windows_x86_64_gnullvm 0.52.5", - "windows_x86_64_msvc 0.52.5", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", ] [[package]] @@ -1851,9 +1875,9 @@ checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" [[package]] name = "windows_aarch64_gnullvm" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" [[package]] name = "windows_aarch64_msvc" @@ -1863,9 +1887,9 @@ checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" [[package]] name = "windows_aarch64_msvc" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" [[package]] name = "windows_i686_gnu" @@ -1875,15 +1899,15 @@ checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" [[package]] name = "windows_i686_gnu" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" [[package]] name = "windows_i686_gnullvm" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" [[package]] name = "windows_i686_msvc" @@ -1893,9 +1917,9 @@ checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" [[package]] name = "windows_i686_msvc" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" [[package]] name = "windows_x86_64_gnu" @@ -1905,9 +1929,9 @@ checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" [[package]] name = "windows_x86_64_gnu" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" [[package]] name = "windows_x86_64_gnullvm" @@ -1917,9 +1941,9 @@ checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" [[package]] name = "windows_x86_64_gnullvm" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" [[package]] name = "windows_x86_64_msvc" @@ -1929,9 +1953,9 @@ checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] name = "windows_x86_64_msvc" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "yansi-term" @@ -2029,26 +2053,27 @@ dependencies = [ [[package]] name = "zerocopy" -version = "0.7.32" +version = "0.7.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74d4d3961e53fa4c9a25a8637fc2bfaf2595b3d3ae34875568a5cf64787716be" +checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" dependencies = [ + "byteorder", "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.7.32" +version = "0.7.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" +checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.77", ] [[package]] name = "zeroize" -version = "1.8.0" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63381fa6624bf92130a6b87c0d07380116f80b565c42cf0d754136f0238359ef" +checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" diff --git a/frameworks/Rust/ohkami/Cargo.toml b/frameworks/Rust/ohkami/Cargo.toml index b6bf50cf97c..04e08b92b0c 100644 --- a/frameworks/Rust/ohkami/Cargo.toml +++ b/frameworks/Rust/ohkami/Cargo.toml @@ -1,13 +1,24 @@ [package] name = "ohkami_framework_benchmarks" -version = "0.19.0" +version = "0.20.0" edition = "2021" authors = ["kanarus "] [dependencies] -ohkami = { version = "=0.19.0", features = ["rt_tokio"] } -tokio = { version = "1.38.0" , features = ["full"] } +ohkami = { version = "=0.20.0", features = ["rt_tokio"] } +tokio = { version = "1.40.0" , features = ["full"] } rand = { version = "0.8.5" , features = ["small_rng"] } -sqlx = { version = "0.7.4" , features = ["postgres", "macros", "runtime-tokio-native-tls"] } +sqlx = { version = "0.8.1" , features = ["postgres", "macros", "runtime-tokio-native-tls"] } yarte = { version = "0.15.7" } futures-util = { version = "0.3.30" } + +[profile.release] +opt-level = 3 +debug = false +debug-assertions = false +lto = true +panic = "abort" +incremental = false +codegen-units = 1 +rpath = false +strip = false \ No newline at end of file diff --git a/frameworks/Rust/ohkami/ohkami.dockerfile b/frameworks/Rust/ohkami/ohkami.dockerfile index b993ec905a5..287f293a061 100644 --- a/frameworks/Rust/ohkami/ohkami.dockerfile +++ b/frameworks/Rust/ohkami/ohkami.dockerfile @@ -1,4 +1,4 @@ -FROM rust:1.79-slim-buster +FROM rust:1.80-slim-bullseye WORKDIR /ohkami_framework_benchmarks ENV DATABASE_URL=postgres://benchmarkdbuser:benchmarkdbpass@tfb-database/hello_world diff --git a/frameworks/Rust/ohkami/src/fangs.rs b/frameworks/Rust/ohkami/src/fangs.rs index 46a19808f46..2dd8e27e5d3 100644 --- a/frameworks/Rust/ohkami/src/fangs.rs +++ b/frameworks/Rust/ohkami/src/fangs.rs @@ -1,5 +1,4 @@ use ohkami::prelude::*; -use crate::Postgres; #[derive(Clone)] @@ -10,41 +9,3 @@ impl FangAction for SetServer { res.headers.set().Server("ohkami"); } } - -impl Postgres { - pub async fn init() -> impl FangAction { - #[derive(Clone)] - pub struct UsePostgres(Postgres); - impl FangAction for UsePostgres { - #[inline(always)] - async fn fore<'a>(&'a self, req: &'a mut Request) -> Result<(), Response> { - Ok(req.memorize(self.0.clone())) - } - } - - macro_rules! load_env { - ($($name:ident as $t:ty)*) => {$( - #[allow(non_snake_case)] - let $name = ::std::env::var(stringify!($name)) - .expect(concat!( - "Failed to load environment variable ", - "`", stringify!($name), "`" - )) - .parse::<$t>() - .unwrap(); - )*}; - } load_env! { - MAX_CONNECTIONS as u32 - MIN_CONNECTIONS as u32 - DATABASE_URL as String - } - - let pool = sqlx::postgres::PgPoolOptions::new() - .max_connections(MAX_CONNECTIONS) - .min_connections(MIN_CONNECTIONS) - .connect(&DATABASE_URL).await - .unwrap(); - - UsePostgres(pool.into()) - } -} diff --git a/frameworks/Rust/ohkami/src/main.rs b/frameworks/Rust/ohkami/src/main.rs index 7473338dc5b..96cc9cc2fbc 100644 --- a/frameworks/Rust/ohkami/src/main.rs +++ b/frameworks/Rust/ohkami/src/main.rs @@ -11,12 +11,16 @@ mod templates; use templates::FortunesTemplate; use ohkami::prelude::*; +use ohkami::format::{JSON, Query}; use ohkami::Memory; #[tokio::main] async fn main() { - Ohkami::with((SetServer, Postgres::init().await), ( + Ohkami::with(( + SetServer, + Memory::new(Postgres::new().await), + ), ( "/json" .GET(json_serialization), "/db" .GET(single_database_query), "/queries" .GET(multiple_database_query), @@ -26,40 +30,44 @@ async fn main() { )).howl("0.0.0.0:8000").await } -async fn json_serialization() -> Message { - Message { +async fn json_serialization() -> JSON { + JSON(Message { message: "Hello, World!" - } + }) } -async fn single_database_query(p: Memory<'_, Postgres>) -> World { - p.select_random_world().await +async fn single_database_query(p: Memory<'_, Postgres>) -> JSON { + let world = p.select_random_world().await; + JSON(world) } -async fn multiple_database_query(q: WorldsQuery<'_>, p: Memory<'_, Postgres>) -> Vec { +async fn multiple_database_query( + Query(q): Query>, + p: Memory<'_, Postgres> +) -> JSON> { let n = q.parse(); - p.select_n_random_worlds(n).await + let worlds = p.select_n_random_worlds(n).await; + JSON(worlds) } async fn fortunes(p: Memory<'_, Postgres>) -> FortunesTemplate { let mut fortunes = p.select_all_fortunes().await; - fortunes.push(Fortune { id: 0, message: String::from("Additional fortune added at request time."), }); fortunes.sort_unstable_by(|a, b| str::cmp(&a.message, &b.message)); - FortunesTemplate { fortunes } } -async fn database_updates(q: WorldsQuery<'_>, p: Memory<'_, Postgres>) -> Vec { +async fn database_updates( + Query(q): Query>, + p: Memory<'_, Postgres> +) -> JSON> { let n = q.parse(); let mut worlds = p.select_n_random_worlds(n).await; - p.update_random_ids_of_worlds(&mut worlds).await; - - worlds + JSON(worlds) } async fn plaintext() -> &'static str { diff --git a/frameworks/Rust/ohkami/src/models.rs b/frameworks/Rust/ohkami/src/models.rs index 55eb8f8fa6d..874dd22a5d7 100644 --- a/frameworks/Rust/ohkami/src/models.rs +++ b/frameworks/Rust/ohkami/src/models.rs @@ -1,8 +1,7 @@ -use ohkami::typed::{Payload, Query}; -use ohkami::builtin::payload::JSON; +use ohkami::serde::{Serialize, Deserialize}; -#[Payload(JSON/S)] +#[derive(Serialize)] pub struct Message { pub message: &'static str, } @@ -14,14 +13,14 @@ pub struct Fortune { } #[derive(sqlx::FromRow)] -#[Payload(JSON/S)] +#[derive(Serialize)] pub struct World { pub id: i32, #[serde(rename="randomNumber")] pub randomnumber: i32, } -#[Query] +#[derive(Deserialize)] pub struct WorldsQuery<'q> { q: Option<&'q str>, } diff --git a/frameworks/Rust/ohkami/src/postgres.rs b/frameworks/Rust/ohkami/src/postgres.rs index e9238d67493..c320e2516e3 100644 --- a/frameworks/Rust/ohkami/src/postgres.rs +++ b/frameworks/Rust/ohkami/src/postgres.rs @@ -6,9 +6,32 @@ use crate::models::{World, Fortune}; #[derive(Clone)] pub struct Postgres(sqlx::PgPool); -impl From for Postgres { - fn from(pgpool: sqlx::PgPool) -> Self { - Self(pgpool) +impl Postgres { + pub async fn new() -> Self { + macro_rules! load_env { + ($($name:ident as $t:ty)*) => {$( + #[allow(non_snake_case)] + let $name = ::std::env::var(stringify!($name)) + .expect(concat!( + "Failed to load environment variable ", + "`", stringify!($name), "`" + )) + .parse::<$t>() + .unwrap(); + )*}; + } load_env! { + MAX_CONNECTIONS as u32 + MIN_CONNECTIONS as u32 + DATABASE_URL as String + } + + let pool = sqlx::postgres::PgPoolOptions::new() + .max_connections(MAX_CONNECTIONS) + .min_connections(MIN_CONNECTIONS) + .connect(&DATABASE_URL).await + .unwrap(); + + Self(pool) } } From 96d08a74c0b2e1392ad60c328a94f7c23e489f60 Mon Sep 17 00:00:00 2001 From: cclilshy Date: Wed, 4 Sep 2024 04:35:23 +0800 Subject: [PATCH 104/204] [PHP/laravel] Add PRipple coroutine engine for Laravel framework (#9239) * [PHP/laravel] Add PRipple coroutine engine for Laravel framework * Style: Normalized code style & display_name adjustment --- frameworks/PHP/laravel/benchmark_config.json | 25 +++++++++- .../PHP/laravel/laravel-pripple.dockerfile | 48 +++++++++++++++++++ 2 files changed, 72 insertions(+), 1 deletion(-) create mode 100644 frameworks/PHP/laravel/laravel-pripple.dockerfile diff --git a/frameworks/PHP/laravel/benchmark_config.json b/frameworks/PHP/laravel/benchmark_config.json index 588dab1e17f..f8421378e51 100644 --- a/frameworks/PHP/laravel/benchmark_config.json +++ b/frameworks/PHP/laravel/benchmark_config.json @@ -138,6 +138,29 @@ "display_name": "laravel-octane [frankenphp]", "notes": "", "versus": "php" + }, + "pripple": { + "json_url": "/json", + "db_url": "/db", + "query_url": "/queries/", + "fortune_url": "/fortunes", + "update_url": "/updates/", + "plaintext_url": "/plaintext", + "port": 8080, + "approach": "Realistic", + "classification": "Fullstack", + "database": "MySQL", + "framework": "laravel", + "language": "PHP", + "flavor": "PHP8.3", + "orm": "Full", + "platform": "PRipple", + "webserver": "PServer", + "os": "Linux", + "database_os": "Linux", + "display_name": "laravel-pripple", + "notes": "", + "versus": "php" } }] -} \ No newline at end of file +} diff --git a/frameworks/PHP/laravel/laravel-pripple.dockerfile b/frameworks/PHP/laravel/laravel-pripple.dockerfile new file mode 100644 index 00000000000..869661a0432 --- /dev/null +++ b/frameworks/PHP/laravel/laravel-pripple.dockerfile @@ -0,0 +1,48 @@ +FROM php:8.3-cli + +RUN apt-get update -yqq >> /dev/null +RUN apt-get install -y libevent-dev \ + libssl-dev \ + pkg-config \ + build-essential \ + unzip >> /dev/null + +RUN docker-php-ext-install pdo_mysql \ + opcache \ + posix \ + pcntl \ + sockets >> /dev/null + +RUN pecl install event >> /dev/null + +RUN docker-php-ext-enable pdo_mysql opcache posix pcntl sockets +RUN docker-php-ext-enable --ini-name zz-event.ini event +RUN echo "opcache.enable_cli=1" >> /usr/local/etc/php/conf.d/docker-php-ext-opcache.ini +RUN echo "opcache.jit=1205" >> /usr/local/etc/php/conf.d/docker-php-ext-opcache.ini +RUN echo "opcache.jit_buffer_size=128M" >> /usr/local/etc/php/conf.d/docker-php-ext-opcache.ini + +COPY --from=composer --link /usr/bin/composer /usr/local/bin/composer + +# Initialize +WORKDIR /laravel +COPY --link . . + +RUN mkdir -p bootstrap/cache \ + storage/logs \ + storage/framework/sessions \ + storage/framework/views \ + storage/framework/cache + +# Configure +RUN echo "PRP_HTTP_LISTEN=http://0.0.0.0:8080" >> .env +RUN echo "PRP_HTTP_COUNT=64" >> .env + +RUN composer install --quiet +RUN php artisan optimize + +RUN composer require cclilshy/p-ripple-drive --quiet +RUN composer update --quiet + +EXPOSE 8080 + +ENTRYPOINT ["php","artisan","p:server","start"] From f83474331848fc9bb33426c1fd3b18c6fe118701 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Deleuze?= Date: Wed, 4 Sep 2024 19:00:23 +0200 Subject: [PATCH 105/204] Optimize Spring samples (#9249) * Optimize spring-webflux - Upgrade to Spring Boot 3.3.3 - Optimize handler implementations - Optimize the router implementation - Use WebFlux.fn configuration for HttpHandler * Optimize spring - Upgrade to Spring Boot 3.3.3 - Use WebMVC.fn instead of `@Controller` - Refine configuration --- frameworks/Java/spring-webflux/pom.xml | 2 +- .../src/main/java/benchmark/App.java | 17 ++++ .../{WebfluxHandler.java => DbHandler.java} | 32 ++----- .../main/java/benchmark/web/JsonHandler.java | 54 ++++++++++++ .../benchmark/{ => web}/ServerFilter.java | 5 +- .../main/java/benchmark/web/TextHandler.java | 37 +++++++++ .../java/benchmark/web/WebfluxRouter.java | 29 ++++--- frameworks/Java/spring/pom.xml | 2 +- frameworks/Java/spring/spring.dockerfile | 2 +- .../Java/spring/src/main/java/hello/App.java | 3 +- .../java/hello/UpdateWorldServiceImpl.java | 5 +- .../DbHandler.java} | 83 ++++++++----------- .../src/main/java/hello/web/JsonHandler.java | 39 +++++++++ .../src/main/java/hello/web/TextHandler.java | 27 ++++++ .../src/main/java/hello/web/WebmvcRouter.java | 32 +++++++ .../spring/src/main/resources/application.yml | 9 +- 16 files changed, 281 insertions(+), 97 deletions(-) rename frameworks/Java/spring-webflux/src/main/java/benchmark/web/{WebfluxHandler.java => DbHandler.java} (74%) create mode 100644 frameworks/Java/spring-webflux/src/main/java/benchmark/web/JsonHandler.java rename frameworks/Java/spring-webflux/src/main/java/benchmark/{ => web}/ServerFilter.java (83%) create mode 100644 frameworks/Java/spring-webflux/src/main/java/benchmark/web/TextHandler.java rename frameworks/Java/spring/src/main/java/hello/{controller/HelloController.java => web/DbHandler.java} (50%) create mode 100644 frameworks/Java/spring/src/main/java/hello/web/JsonHandler.java create mode 100644 frameworks/Java/spring/src/main/java/hello/web/TextHandler.java create mode 100644 frameworks/Java/spring/src/main/java/hello/web/WebmvcRouter.java diff --git a/frameworks/Java/spring-webflux/pom.xml b/frameworks/Java/spring-webflux/pom.xml index 4dd5b09698c..c15b211c92d 100644 --- a/frameworks/Java/spring-webflux/pom.xml +++ b/frameworks/Java/spring-webflux/pom.xml @@ -13,7 +13,7 @@ org.springframework.boot spring-boot-starter-parent - 3.3.1 + 3.3.3 diff --git a/frameworks/Java/spring-webflux/src/main/java/benchmark/App.java b/frameworks/Java/spring-webflux/src/main/java/benchmark/App.java index 37ff0a80ff0..c574863a9a9 100644 --- a/frameworks/Java/spring-webflux/src/main/java/benchmark/App.java +++ b/frameworks/Java/spring-webflux/src/main/java/benchmark/App.java @@ -1,13 +1,30 @@ package benchmark; +import benchmark.web.ServerFilter; + import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.Bean; +import org.springframework.http.server.reactive.HttpHandler; import org.springframework.scheduling.annotation.EnableScheduling; +import org.springframework.web.reactive.function.server.HandlerStrategies; +import org.springframework.web.reactive.function.server.RouterFunction; +import org.springframework.web.reactive.function.server.RouterFunctions; +import org.springframework.web.reactive.function.server.ServerResponse; +import org.springframework.web.reactive.result.view.ViewResolver; +import org.springframework.web.server.WebHandler; +import org.springframework.web.server.adapter.WebHttpHandlerBuilder; @SpringBootApplication @EnableScheduling public class App { + @Bean + public HttpHandler httpHandler(RouterFunction route, ServerFilter serverFilter, ViewResolver viewResolver) { + WebHandler webHandler = RouterFunctions.toWebHandler(route, HandlerStrategies.builder().viewResolver(viewResolver).build()); + return WebHttpHandlerBuilder.webHandler(webHandler).filter(serverFilter).build(); + } + public static void main(String[] args) { SpringApplication.run(App.class, args); } diff --git a/frameworks/Java/spring-webflux/src/main/java/benchmark/web/WebfluxHandler.java b/frameworks/Java/spring-webflux/src/main/java/benchmark/web/DbHandler.java similarity index 74% rename from frameworks/Java/spring-webflux/src/main/java/benchmark/web/WebfluxHandler.java rename to frameworks/Java/spring-webflux/src/main/java/benchmark/web/DbHandler.java index a7516af6636..bafddaf83c6 100644 --- a/frameworks/Java/spring-webflux/src/main/java/benchmark/web/WebfluxHandler.java +++ b/frameworks/Java/spring-webflux/src/main/java/benchmark/web/DbHandler.java @@ -2,11 +2,9 @@ import java.util.Collections; import java.util.List; -import java.util.Optional; import java.util.concurrent.ThreadLocalRandom; import benchmark.model.Fortune; -import benchmark.model.Message; import benchmark.model.World; import benchmark.repository.DbRepository; import reactor.core.publisher.Flux; @@ -21,26 +19,14 @@ import static java.util.Comparator.comparing; @Component -public class WebfluxHandler { +public class DbHandler { private final DbRepository dbRepository; - public WebfluxHandler(DbRepository dbRepository) { + public DbHandler(DbRepository dbRepository) { this.dbRepository = dbRepository; } - public Mono plaintext(ServerRequest request) { - return ServerResponse.ok() - .contentType(MediaType.TEXT_PLAIN) - .bodyValue("Hello, World!"); - } - - public Mono json(ServerRequest request) { - return ServerResponse.ok() - .contentType(MediaType.APPLICATION_JSON) - .bodyValue(new Message("Hello, World!")); - } - public Mono db(ServerRequest request) { int id = randomWorldNumber(); Mono world = dbRepository.getWorld(id) @@ -52,7 +38,7 @@ public Mono db(ServerRequest request) { } public Mono queries(ServerRequest request) { - int queries = getQueries(request); + int queries = parseQueryCount(request.queryParams().getFirst("queries")); Mono> worlds = Flux.range(0, queries) .flatMap(i -> dbRepository.getWorld(randomWorldNumber())) @@ -64,13 +50,13 @@ public Mono queries(ServerRequest request) { }); } - private static int parseQueryCount(Optional maybeTextValue) { - if (!maybeTextValue.isPresent()) { + private static int parseQueryCount(String maybeTextValue) { + if (maybeTextValue == null) { return 1; } int parsedValue; try { - parsedValue = Integer.parseInt(maybeTextValue.get()); + parsedValue = Integer.parseInt(maybeTextValue); } catch (NumberFormatException e) { return 1; } @@ -78,7 +64,7 @@ private static int parseQueryCount(Optional maybeTextValue) { } public Mono updates(ServerRequest request) { - int queries = getQueries(request); + int queries = parseQueryCount(request.queryParams().getFirst("queries")); Mono> worlds = Flux.range(0, queries) .flatMap(i -> dbRepository.findAndUpdateWorld(randomWorldNumber(), randomWorldNumber())) @@ -101,10 +87,6 @@ public Mono fortunes(ServerRequest request) { .render("fortunes", Collections.singletonMap("fortunes", result)); } - private static int getQueries(ServerRequest request) { - return parseQueryCount(request.queryParam("queries")); - } - private static int randomWorldNumber() { return 1 + ThreadLocalRandom.current().nextInt(10000); } diff --git a/frameworks/Java/spring-webflux/src/main/java/benchmark/web/JsonHandler.java b/frameworks/Java/spring-webflux/src/main/java/benchmark/web/JsonHandler.java new file mode 100644 index 00000000000..6f4bc19249f --- /dev/null +++ b/frameworks/Java/spring-webflux/src/main/java/benchmark/web/JsonHandler.java @@ -0,0 +1,54 @@ +package benchmark.web; + +import java.util.Map; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.ObjectWriter; +import reactor.core.publisher.Mono; + +import org.springframework.core.io.buffer.DataBuffer; +import org.springframework.core.io.buffer.DataBufferFactory; +import org.springframework.http.HttpHeaders; +import org.springframework.http.MediaType; +import org.springframework.stereotype.Component; +import org.springframework.web.reactive.function.server.HandlerFunction; +import org.springframework.web.reactive.function.server.ServerRequest; +import org.springframework.web.reactive.function.server.ServerResponse; + +@Component +public class JsonHandler implements HandlerFunction { + + private final ObjectWriter writer; + + public JsonHandler(ObjectMapper objectMapper) { + this.writer = objectMapper.writerFor(Map.class); + } + + @Override + public Mono handle(ServerRequest request) { + return ServerResponse.ok() + .body((message, context) -> { + DataBuffer buffer = serialize(request, Map.of("message", "Hello, world!")); + HttpHeaders headers = message.getHeaders(); + headers.setContentLength(buffer.readableByteCount()); + headers.add(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE); + return message.writeWith(Mono.just(buffer)); + }); + } + + private DataBuffer serialize(ServerRequest request, Object object) { + try { + byte[] bytes = this.writer.writeValueAsBytes(object); + return bufferFactory(request).wrap(bytes); + } + catch (JsonProcessingException ex) { + throw new RuntimeException(ex); + } + } + + private static DataBufferFactory bufferFactory(ServerRequest request) { + return request.exchange().getResponse().bufferFactory(); + } + +} \ No newline at end of file diff --git a/frameworks/Java/spring-webflux/src/main/java/benchmark/ServerFilter.java b/frameworks/Java/spring-webflux/src/main/java/benchmark/web/ServerFilter.java similarity index 83% rename from frameworks/Java/spring-webflux/src/main/java/benchmark/ServerFilter.java rename to frameworks/Java/spring-webflux/src/main/java/benchmark/web/ServerFilter.java index 685ac39e6ad..38357eefdb2 100644 --- a/frameworks/Java/spring-webflux/src/main/java/benchmark/ServerFilter.java +++ b/frameworks/Java/spring-webflux/src/main/java/benchmark/web/ServerFilter.java @@ -1,6 +1,5 @@ package benchmark.web; -import io.netty.handler.codec.http.HttpHeaderNames; import org.springframework.http.HttpHeaders; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; @@ -28,8 +27,8 @@ public void updateDate() { @Override public Mono filter(ServerWebExchange exchange, WebFilterChain chain) { HttpHeaders headers = exchange.getResponse().getHeaders(); - headers.add(HttpHeaderNames.SERVER.toString(), SERVER_NAME); - headers.add(HttpHeaderNames.DATE.toString(), this.date); + headers.add(HttpHeaders.SERVER, SERVER_NAME); + headers.add(HttpHeaders.DATE, this.date); return chain.filter(exchange); } } \ No newline at end of file diff --git a/frameworks/Java/spring-webflux/src/main/java/benchmark/web/TextHandler.java b/frameworks/Java/spring-webflux/src/main/java/benchmark/web/TextHandler.java new file mode 100644 index 00000000000..8abac92606d --- /dev/null +++ b/frameworks/Java/spring-webflux/src/main/java/benchmark/web/TextHandler.java @@ -0,0 +1,37 @@ +package benchmark.web; + +import java.nio.charset.StandardCharsets; + +import reactor.core.publisher.Mono; + +import org.springframework.core.io.buffer.DataBufferFactory; +import org.springframework.http.HttpHeaders; +import org.springframework.http.MediaType; +import org.springframework.stereotype.Component; +import org.springframework.web.reactive.function.server.HandlerFunction; +import org.springframework.web.reactive.function.server.ServerRequest; +import org.springframework.web.reactive.function.server.ServerResponse; + +@Component +public class TextHandler implements HandlerFunction { + + private static final byte[] TEXT_BODY = "Hello, World!".getBytes(StandardCharsets.UTF_8); + + private static final String TEXT_BODY_LENGTH = String.valueOf(TEXT_BODY.length); + + @Override + public Mono handle(ServerRequest request) { + return ServerResponse.ok() + .body((message, context) -> { + HttpHeaders headers = message.getHeaders(); + headers.add(HttpHeaders.CONTENT_LENGTH, TEXT_BODY_LENGTH); + headers.add(HttpHeaders.CONTENT_TYPE, MediaType.TEXT_PLAIN_VALUE); + return message.writeWith(Mono.just(bufferFactory(request).wrap(TEXT_BODY))); + }); + } + + private static DataBufferFactory bufferFactory(ServerRequest request) { + return request.exchange().getResponse().bufferFactory(); + } + +} \ No newline at end of file diff --git a/frameworks/Java/spring-webflux/src/main/java/benchmark/web/WebfluxRouter.java b/frameworks/Java/spring-webflux/src/main/java/benchmark/web/WebfluxRouter.java index 061797738c2..1499dc4f839 100644 --- a/frameworks/Java/spring-webflux/src/main/java/benchmark/web/WebfluxRouter.java +++ b/frameworks/Java/spring-webflux/src/main/java/benchmark/web/WebfluxRouter.java @@ -1,23 +1,32 @@ package benchmark.web; +import reactor.core.publisher.Mono; + import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.web.reactive.function.server.HandlerFunction; import org.springframework.web.reactive.function.server.RouterFunction; -import org.springframework.web.reactive.function.server.RouterFunctions; import org.springframework.web.reactive.function.server.ServerResponse; @Configuration public class WebfluxRouter { @Bean - public RouterFunction route(WebfluxHandler handler) { - return RouterFunctions.route() - .GET("/plaintext", handler::plaintext) - .GET("/json", handler::json) - .GET("/db", handler::db) - .GET("/queries", handler::queries) - .GET("/updates", handler::updates) - .GET("/fortunes", handler::fortunes) - .build(); + public RouterFunction route( + TextHandler textHandler, JsonHandler jsonHandler, DbHandler dbHandler) { + + return request -> { + HandlerFunction fn = switch (request.uri().getRawPath()) { + case "/plaintext" -> textHandler; + case "/json" -> jsonHandler; + case "/db" -> dbHandler::db; + case "/queries" -> dbHandler::queries; + case "/updates" -> dbHandler::updates; + case "/fortunes" -> dbHandler::fortunes; + default -> r -> ServerResponse.notFound().build(); + }; + return Mono.just(fn); + }; } + } \ No newline at end of file diff --git a/frameworks/Java/spring/pom.xml b/frameworks/Java/spring/pom.xml index 9f131b9a23f..4a8d36e9749 100644 --- a/frameworks/Java/spring/pom.xml +++ b/frameworks/Java/spring/pom.xml @@ -11,7 +11,7 @@ org.springframework.boot spring-boot-starter-parent - 3.3.1 + 3.3.3 diff --git a/frameworks/Java/spring/spring.dockerfile b/frameworks/Java/spring/spring.dockerfile index 0598e9c1f28..f52c1f36df1 100644 --- a/frameworks/Java/spring/spring.dockerfile +++ b/frameworks/Java/spring/spring.dockerfile @@ -12,4 +12,4 @@ RUN java -Djarmode=tools -jar app.jar extract EXPOSE 8080 -CMD ["java", "-XX:+DisableExplicitGC", "-XX:+UseStringDeduplication", "-Dlogging.level.root=OFF", "-jar", "app/app.jar", "--spring.profiles.active=jpa"] \ No newline at end of file +CMD ["java", "-XX:+DisableExplicitGC", "-XX:+UseStringDeduplication", "-Dlogging.level.root=OFF", "-jar", "app/app.jar", "--spring.profiles.active=jdbc"] \ No newline at end of file diff --git a/frameworks/Java/spring/src/main/java/hello/App.java b/frameworks/Java/spring/src/main/java/hello/App.java index d0c13e06844..0484b46517e 100644 --- a/frameworks/Java/spring/src/main/java/hello/App.java +++ b/frameworks/Java/spring/src/main/java/hello/App.java @@ -4,8 +4,6 @@ import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.boot.autoconfigure.data.mongo.MongoRepositoriesAutoConfiguration; -import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties; import org.springframework.boot.context.event.ApplicationReadyEvent; import org.springframework.context.annotation.Bean; @@ -35,4 +33,5 @@ DataSource datasource(DataSourceProperties dataSourceProperties) { return dataSource; } + } diff --git a/frameworks/Java/spring/src/main/java/hello/UpdateWorldServiceImpl.java b/frameworks/Java/spring/src/main/java/hello/UpdateWorldServiceImpl.java index b59680aef5c..2bd4304a9ee 100644 --- a/frameworks/Java/spring/src/main/java/hello/UpdateWorldServiceImpl.java +++ b/frameworks/Java/spring/src/main/java/hello/UpdateWorldServiceImpl.java @@ -3,7 +3,8 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import hello.controller.HelloController; +import hello.web.DbHandler; +import hello.web.WebmvcRouter; import hello.model.World; import hello.repository.DbRepository; @@ -33,7 +34,7 @@ public World updateWorld(int worldId) { int newRandomNumber; do { - newRandomNumber = HelloController.randomWorldNumber(); + newRandomNumber = DbHandler.randomWorldNumber(); } while (newRandomNumber == world.randomnumber); return dbRepository.updateWorld(world, newRandomNumber); diff --git a/frameworks/Java/spring/src/main/java/hello/controller/HelloController.java b/frameworks/Java/spring/src/main/java/hello/web/DbHandler.java similarity index 50% rename from frameworks/Java/spring/src/main/java/hello/controller/HelloController.java rename to frameworks/Java/spring/src/main/java/hello/web/DbHandler.java index 5c11b82ac66..1611cf21170 100644 --- a/frameworks/Java/spring/src/main/java/hello/controller/HelloController.java +++ b/frameworks/Java/spring/src/main/java/hello/web/DbHandler.java @@ -1,79 +1,68 @@ -package hello.controller; +package hello.web; -import static java.util.Comparator.comparing; - -import java.util.List; import java.util.concurrent.ThreadLocalRandom; import java.util.stream.IntStream; -import hello.model.Message; -import jakarta.servlet.http.HttpServletResponse; -import org.springframework.http.MediaType; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.ModelAttribute; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.RestController; - import hello.UpdateWorldService; import hello.model.Fortune; import hello.model.World; import hello.repository.DbRepository; -@RestController -public final class HelloController { +import org.springframework.http.HttpHeaders; +import org.springframework.http.MediaType; +import org.springframework.stereotype.Component; +import org.springframework.web.servlet.function.RenderingResponse; +import org.springframework.web.servlet.function.ServerRequest; +import org.springframework.web.servlet.function.ServerResponse; + +import static java.util.Comparator.comparing; + +@Component +public class DbHandler { private DbRepository dbRepository; private UpdateWorldService updateWorldService; - public HelloController( - DbRepository dbRepository, - UpdateWorldService updateWorldService) { + public DbHandler(DbRepository dbRepository, UpdateWorldService updateWorldService) { this.dbRepository = dbRepository; this.updateWorldService = updateWorldService; } - @GetMapping("/plaintext") - String plaintext(HttpServletResponse response) { - response.setContentType(MediaType.TEXT_PLAIN_VALUE); - return "Hello, World!"; - } - - @GetMapping("/json") - Message json(HttpServletResponse response) { - response.setContentType(MediaType.APPLICATION_JSON_VALUE); - return new Message("Hello, World!"); + ServerResponse db(ServerRequest request) { + return ServerResponse.ok() + .contentType(MediaType.APPLICATION_JSON) + .body(dbRepository.getWorld(randomWorldNumber())); } - @GetMapping("/db") - World db(HttpServletResponse response) { - response.setContentType(MediaType.APPLICATION_JSON_VALUE); - return dbRepository.getWorld(randomWorldNumber()); - } - - @GetMapping("/queries") - World[] queries(HttpServletResponse response, @RequestParam(required = false) String queries) { - response.setContentType(MediaType.APPLICATION_JSON_VALUE); - return randomWorldNumbers().mapToObj(dbRepository::getWorld).limit(parseQueryCount(queries)) + ServerResponse queries(ServerRequest request) { + String queries = request.params().getFirst("queries"); + World[] worlds = randomWorldNumbers() + .mapToObj(dbRepository::getWorld).limit(parseQueryCount(queries)) .toArray(World[]::new); + return ServerResponse.ok() + .contentType(MediaType.APPLICATION_JSON) + .body(worlds); } - @GetMapping("/updates") - World[] updates(HttpServletResponse response, @RequestParam(required = false) String queries) { - response.setContentType(MediaType.APPLICATION_JSON_VALUE); - return randomWorldNumbers() + ServerResponse updates(ServerRequest request) { + String queries = request.params().getFirst("queries"); + World[] worlds = randomWorldNumbers() .mapToObj(id -> updateWorldService.updateWorld(id)) .limit(parseQueryCount(queries)).toArray(World[]::new); + return ServerResponse.ok() + .contentType(MediaType.APPLICATION_JSON) + .body(worlds); } - @GetMapping("/fortunes") - @ModelAttribute("fortunes") - List fortunes(HttpServletResponse response) { - response.setContentType(MediaType.TEXT_HTML_VALUE); + ServerResponse fortunes(ServerRequest request) { var fortunes = dbRepository.fortunes(); - fortunes.add(new Fortune(0, "Additional fortune added at request time.")); fortunes.sort(comparing(fortune -> fortune.message)); - return fortunes; + return RenderingResponse + .create("fortunes") + .modelAttribute("fortunes", fortunes) + .header(HttpHeaders.CONTENT_TYPE, MediaType.TEXT_HTML_VALUE) + .build(); } private static final int MIN_WORLD_NUMBER = 1; diff --git a/frameworks/Java/spring/src/main/java/hello/web/JsonHandler.java b/frameworks/Java/spring/src/main/java/hello/web/JsonHandler.java new file mode 100644 index 00000000000..c6690811eca --- /dev/null +++ b/frameworks/Java/spring/src/main/java/hello/web/JsonHandler.java @@ -0,0 +1,39 @@ +package hello.web; + +import java.util.Map; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.ObjectWriter; + +import org.springframework.http.HttpHeaders; +import org.springframework.http.MediaType; +import org.springframework.stereotype.Component; +import org.springframework.web.servlet.function.HandlerFunction; +import org.springframework.web.servlet.function.ServerRequest; +import org.springframework.web.servlet.function.ServerResponse; + +@Component +public class JsonHandler implements HandlerFunction { + + private final ObjectWriter writer; + + public JsonHandler(ObjectMapper objectMapper) { + this.writer = objectMapper.writerFor(Map.class); + } + + @Override + public ServerResponse handle(ServerRequest request) { + try { + byte[] body = this.writer.writeValueAsBytes(Map.of("message", "Hello, world!")); + return ServerResponse.ok() + .contentLength(body.length) + .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE) + .body(body); + } + catch (JsonProcessingException ex) { + throw new RuntimeException(ex); + } + } + +} diff --git a/frameworks/Java/spring/src/main/java/hello/web/TextHandler.java b/frameworks/Java/spring/src/main/java/hello/web/TextHandler.java new file mode 100644 index 00000000000..b70b3010268 --- /dev/null +++ b/frameworks/Java/spring/src/main/java/hello/web/TextHandler.java @@ -0,0 +1,27 @@ +package hello.web; + +import java.nio.charset.StandardCharsets; + +import org.springframework.http.HttpHeaders; +import org.springframework.http.MediaType; +import org.springframework.stereotype.Component; +import org.springframework.web.servlet.function.HandlerFunction; +import org.springframework.web.servlet.function.ServerRequest; +import org.springframework.web.servlet.function.ServerResponse; + +@Component +public class TextHandler implements HandlerFunction { + + private static final byte[] TEXT_BODY = "Hello, World!".getBytes(StandardCharsets.UTF_8); + + private static final String TEXT_BODY_LENGTH = String.valueOf(TEXT_BODY.length); + + @Override + public ServerResponse handle(ServerRequest request) { + return ServerResponse.ok() + .header(HttpHeaders.CONTENT_LENGTH, TEXT_BODY_LENGTH) + .header(HttpHeaders.CONTENT_TYPE, MediaType.TEXT_PLAIN_VALUE) + .body(TEXT_BODY); + } + +} diff --git a/frameworks/Java/spring/src/main/java/hello/web/WebmvcRouter.java b/frameworks/Java/spring/src/main/java/hello/web/WebmvcRouter.java new file mode 100644 index 00000000000..0a5810affd2 --- /dev/null +++ b/frameworks/Java/spring/src/main/java/hello/web/WebmvcRouter.java @@ -0,0 +1,32 @@ +package hello.web; + +import java.util.Optional; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.servlet.function.HandlerFunction; +import org.springframework.web.servlet.function.RouterFunction; +import org.springframework.web.servlet.function.ServerResponse; + +@Configuration +public class WebmvcRouter { + + @Bean + public RouterFunction route( + TextHandler textHandler, + JsonHandler jsonHandler, + DbHandler dbHandler) { + + return request -> Optional.of((HandlerFunction) r -> + switch (r.uri().getRawPath()) { + case "/plaintext" -> textHandler.handle(r); + case "/json" -> jsonHandler.handle(r); + case "/db" -> dbHandler.db(r); + case "/queries" -> dbHandler.queries(r); + case "/updates" -> dbHandler.updates(r); + case "/fortunes" -> dbHandler.fortunes(r); + default -> ServerResponse.notFound().build(); + }); + } +} + diff --git a/frameworks/Java/spring/src/main/resources/application.yml b/frameworks/Java/spring/src/main/resources/application.yml index 4796669a8e5..4f6592dc53b 100644 --- a/frameworks/Java/spring/src/main/resources/application.yml +++ b/frameworks/Java/spring/src/main/resources/application.yml @@ -1,12 +1,10 @@ --- spring: - jpa: - open-in-view: false config: activate: on-profile: jdbc autoconfigure: - exclude: org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration,org.springframework.boot.autoconfigure.data.jpa.JpaRepositoriesAutoConfiguration,org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration,org.springframework.boot.autoconfigure.data.mongo.MongoRepositoriesAutoConfiguration + exclude: org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration,org.springframework.boot.autoconfigure.data.jpa.JpaRepositoriesAutoConfiguration,org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration,org.springframework.boot.autoconfigure.data.mongo.MongoDataAutoConfiguration,org.springframework.boot.autoconfigure.data.mongo.MongoRepositoriesAutoConfiguration,org.springframework.boot.autoconfigure.data.web.SpringDataWebAutoConfiguration --- spring: @@ -31,7 +29,7 @@ spring: activate: on-profile: jpa autoconfigure: - exclude: org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration,org.springframework.boot.autoconfigure.data.mongo.MongoRepositoriesAutoConfiguration + exclude: org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration,org.springframework.boot.autoconfigure.data.mongo.MongoRepositoriesAutoConfiguration,org.springframework.boot.autoconfigure.data.mongo.MongoDataAutoConfiguration,org.springframework.boot.autoconfigure.data.web.SpringDataWebAutoConfiguration jpa: database-platform: org.hibernate.dialect.PostgreSQLDialect @@ -41,7 +39,7 @@ spring: activate: on-profile: mongo autoconfigure: - exclude: org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration,org.springframework.boot.autoconfigure.data.jpa.JpaRepositoriesAutoConfiguration,org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration + exclude: org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration,org.springframework.boot.autoconfigure.data.jpa.JpaRepositoriesAutoConfiguration,org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration,org.springframework.boot.autoconfigure.data.web.SpringDataWebAutoConfiguration spring.data.mongodb: host: tfb-database @@ -55,3 +53,4 @@ spring: server.server-header: Spring server.servlet.encoding.force: true +spring.jpa.open-in-view: false From 8afa827e93500685666071353455ce281c4c69c2 Mon Sep 17 00:00:00 2001 From: Joan Miquel Date: Thu, 5 Sep 2024 18:30:18 +0200 Subject: [PATCH 106/204] [php] Fix Leaf v3.6 dockerfiles (#9250) * Leafphp fix dockerfiles * Clean event install --- frameworks/PHP/leaf/leaf-workerman.dockerfile | 15 ++++++++------- frameworks/PHP/leaf/leaf.dockerfile | 8 ++++---- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/frameworks/PHP/leaf/leaf-workerman.dockerfile b/frameworks/PHP/leaf/leaf-workerman.dockerfile index eaa11589d3a..ddcc5dc928c 100644 --- a/frameworks/PHP/leaf/leaf-workerman.dockerfile +++ b/frameworks/PHP/leaf/leaf-workerman.dockerfile @@ -1,4 +1,4 @@ -FROM ubuntu:22.04 +FROM ubuntu:24.04 ARG DEBIAN_FRONTEND=noninteractive @@ -7,21 +7,22 @@ RUN LC_ALL=C.UTF-8 add-apt-repository ppa:ondrej/php > /dev/null && \ apt-get update -yqq > /dev/null && apt-get upgrade -yqq > /dev/null RUN apt-get update -yqq > /dev/null && apt-get install -yqq git \ - php8.3-cli php8.3-mysql php8.3-mbstring php8.3-xml php8.3-curl > /dev/null + php8.3-cli php8.3-mysql php8.3-mbstring php8.3-xml php8.3-curl php8.3-zip > /dev/null COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer -RUN apt-get install -y php-pear php8.3-dev libevent-dev > /dev/null -RUN pecl install event-3.1.3 > /dev/null && echo "extension=event.so" > /etc/php/8.3/cli/conf.d/event.ini +RUN apt-get install -y libevent-dev php8.3-dev > /dev/null \ + && pecl install event-3.1.4 > /dev/null \ + && echo "extension=event.so" > /etc/php/8.3/cli/conf.d/event.ini -COPY deploy/conf/cli-php.ini /etc/php/8.3/cli/php.ini +COPY --link deploy/conf/cli-php.ini /etc/php/8.3/cli/php.ini -ADD ./ /leaf WORKDIR /leaf +COPY --link . . EXPOSE 8080 -RUN composer install --optimize-autoloader --classmap-authoritative --no-dev --quiet +RUN composer install --optimize-autoloader --classmap-authoritative --no-dev --quiet RUN composer require joanhey/adapterman:^0.6 --quiet diff --git a/frameworks/PHP/leaf/leaf.dockerfile b/frameworks/PHP/leaf/leaf.dockerfile index 167a5af7039..52a4c2f704c 100644 --- a/frameworks/PHP/leaf/leaf.dockerfile +++ b/frameworks/PHP/leaf/leaf.dockerfile @@ -1,4 +1,4 @@ -FROM ubuntu:22.04 +FROM ubuntu:24.04 ARG DEBIAN_FRONTEND=noninteractive @@ -7,14 +7,14 @@ RUN LC_ALL=C.UTF-8 add-apt-repository ppa:ondrej/php > /dev/null && \ apt-get update -yqq > /dev/null && apt-get upgrade -yqq > /dev/null RUN apt-get install -yqq nginx git unzip \ - php8.3 php8.3-common php8.3-cli php8.3-fpm php8.3-mysql php8.3-xml php8.3-curl > /dev/null + php8.3-cli php8.3-fpm php8.3-mysql php8.3-xml php8.3-curl php8.3-zip > /dev/null COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer -COPY deploy/conf/* /etc/php/8.3/fpm/ +COPY --link deploy/conf/* /etc/php/8.3/fpm/ -ADD ./ /leaf WORKDIR /leaf +COPY --link . . RUN if [ $(nproc) = 2 ]; then sed -i "s|pm.max_children = 1024|pm.max_children = 512|g" /etc/php/8.3/fpm/php-fpm.conf ; fi; From 91cefe6b137714379b5c5f182e3ef63a409418bb Mon Sep 17 00:00:00 2001 From: fakeshadow <24548779@qq.com> Date: Fri, 6 Sep 2024 04:03:14 +0800 Subject: [PATCH 107/204] [xitca-web] add connection pool (#9252) * [xitca-web] connection pool * fix plaintext. * update dep * simplify api --- frameworks/Rust/xitca-web/Cargo.lock | 43 ++++-- frameworks/Rust/xitca-web/Cargo.toml | 2 +- frameworks/Rust/xitca-web/rustfmt.toml | 1 + frameworks/Rust/xitca-web/src/db.rs | 169 ++++++++++++--------- frameworks/Rust/xitca-web/src/db_diesel.rs | 6 +- frameworks/Rust/xitca-web/src/main.rs | 55 +++---- frameworks/Rust/xitca-web/src/main_axum.rs | 24 +-- frameworks/Rust/xitca-web/src/main_iou.rs | 56 ++----- frameworks/Rust/xitca-web/src/main_sync.rs | 10 +- frameworks/Rust/xitca-web/src/ser.rs | 73 ++++++--- frameworks/Rust/xitca-web/src/util.rs | 4 +- 11 files changed, 234 insertions(+), 209 deletions(-) create mode 100644 frameworks/Rust/xitca-web/rustfmt.toml diff --git a/frameworks/Rust/xitca-web/Cargo.lock b/frameworks/Rust/xitca-web/Cargo.lock index 1f1f0e18a74..00bf2423449 100644 --- a/frameworks/Rust/xitca-web/Cargo.lock +++ b/frameworks/Rust/xitca-web/Cargo.lock @@ -19,9 +19,9 @@ checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" [[package]] name = "async-trait" -version = "0.1.81" +version = "0.1.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e0c28dcc82d7c8ead5cb13beb15405b57b8546e93215673ff8ca0349a028107" +checksum = "a27b8a3a6e1a44fa4c8baf1f653e4172e81486d4941f2237e20dc2d0cf4ddff1" dependencies = [ "proc-macro2", "quote", @@ -149,9 +149,9 @@ checksum = "8318a53db07bb3f8dca91a600466bdb3f2eaadeedfdbcf02e1accbad9271ba50" [[package]] name = "cc" -version = "1.1.15" +version = "1.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57b6a275aa2903740dc87da01c62040406b8812552e97129a63ea8850a17c6e6" +checksum = "e9d013ecb737093c0e86b151a7b837993cf9ec6c502946cfb44bedc392421e0b" dependencies = [ "shlex", ] @@ -218,9 +218,9 @@ dependencies = [ [[package]] name = "diesel" -version = "2.2.3" +version = "2.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65e13bab2796f412722112327f3e575601a3e9cdcbe426f0d30dbf43f3f5dc71" +checksum = "158fe8e2e68695bd615d7e4f3227c0727b151330d3e253b525086c348d055d5e" dependencies = [ "bitflags 2.6.0", "byteorder", @@ -631,6 +631,24 @@ version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" +[[package]] +name = "phf" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc" +dependencies = [ + "phf_shared", +] + +[[package]] +name = "phf_shared" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90fcb95eef784c2ac79119d1dd819e162b5da872ce6f3c3abe1e8ca1c082f72b" +dependencies = [ + "siphasher", +] + [[package]] name = "pin-project" version = "1.1.5" @@ -869,9 +887,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.127" +version = "1.0.128" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8043c06d9f82bd7271361ed64f415fe5e12a77fdb52e573e7f06a516dea329ad" +checksum = "6ff5456707a1de34e7e37f2a6fd3d3f808c318259cbd01ab6377795054b483d8" dependencies = [ "itoa", "memchr", @@ -927,6 +945,12 @@ dependencies = [ "libc", ] +[[package]] +name = "siphasher" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" + [[package]] name = "slab" version = "0.4.9" @@ -1319,10 +1343,11 @@ dependencies = [ [[package]] name = "xitca-postgres" version = "0.1.0" -source = "git+https://github.com/HFQR/xitca-web.git?rev=6870448#687044829f0e89bab3efafcf7fb53e53167ad32c" +source = "git+https://github.com/HFQR/xitca-web.git?rev=9835c0b#9835c0b79ebd77f01b74e3ccb1c9893f022db9f3" dependencies = [ "fallible-iterator", "percent-encoding", + "phf", "postgres-protocol", "postgres-types", "tokio", diff --git a/frameworks/Rust/xitca-web/Cargo.toml b/frameworks/Rust/xitca-web/Cargo.toml index 84eb12264b3..1d6ccc17751 100644 --- a/frameworks/Rust/xitca-web/Cargo.toml +++ b/frameworks/Rust/xitca-web/Cargo.toml @@ -95,5 +95,5 @@ codegen-units = 1 panic = "abort" [patch.crates-io] -xitca-postgres = { git = "https://github.com/HFQR/xitca-web.git", rev = "6870448" } +xitca-postgres = { git = "https://github.com/HFQR/xitca-web.git", rev = "9835c0b" } mio = { git = "https://github.com/fakeshadow/mio", rev = "9bae6012b7ecfc6083350785f71a5e8265358178" } diff --git a/frameworks/Rust/xitca-web/rustfmt.toml b/frameworks/Rust/xitca-web/rustfmt.toml new file mode 100644 index 00000000000..866c7561055 --- /dev/null +++ b/frameworks/Rust/xitca-web/rustfmt.toml @@ -0,0 +1 @@ +max_width = 120 \ No newline at end of file diff --git a/frameworks/Rust/xitca-web/src/db.rs b/frameworks/Rust/xitca-web/src/db.rs index 276eb93ec9e..0b7a18601fb 100644 --- a/frameworks/Rust/xitca-web/src/db.rs +++ b/frameworks/Rust/xitca-web/src/db.rs @@ -1,9 +1,7 @@ use std::fmt::Write; use xitca_io::bytes::BytesMut; -use xitca_postgres::{ - pipeline::Pipeline, statement::Statement, AsyncLendingIterator, SharedClient, -}; +use xitca_postgres::{pipeline::Pipeline, AsyncLendingIterator, Pool, Type}; use super::{ ser::{Fortune, Fortunes, World}, @@ -11,64 +9,63 @@ use super::{ }; pub struct Client { - client: SharedClient, + pool: Pool, #[cfg(not(feature = "pg-sync"))] shared: std::cell::RefCell, #[cfg(feature = "pg-sync")] shared: std::sync::Mutex, - fortune: Statement, - world: Statement, - updates: Box<[Statement]>, + updates: Box<[Box]>, } type Shared = (Rand, BytesMut); -pub async fn create() -> HandleResult { - let mut client = SharedClient::new(DB_URL.to_string()).await?; +const FORTUNE_SQL: &str = "SELECT * FROM fortune"; - let fortune = client.prepare_cached("SELECT * FROM fortune", &[]).await?; +const FORTUNE_SQL_TYPES: &[Type] = &[]; - let world = client - .prepare_cached("SELECT * FROM world WHERE id=$1", &[]) - .await?; +const WORLD_SQL: &str = "SELECT * FROM world WHERE id=$1"; - let mut updates = Vec::new(); +const WORLD_SQL_TYPES: &[Type] = &[Type::INT4]; - // a dummy statement as placeholder of 0 index. - // avoid off by one calculation when using non zero u16 as slicing index. - updates.push(Statement::default()); +fn update_query(num: usize) -> Box { + const PREFIX: &str = "UPDATE world SET randomNumber = w.r FROM (VALUES "; + const SUFFIX: &str = ") AS w (i,r) WHERE world.id = w.i"; - for num in 1..=500u16 { - let mut pl = 1; - let mut q = String::new(); - q.push_str("UPDATE world SET randomnumber = CASE id "); - for _ in 1..=num { - let _ = write!(&mut q, "when ${} then ${} ", pl, pl + 1); - pl += 2; - } - q.push_str("ELSE randomnumber END WHERE id IN ("); - for _ in 1..=num { - let _ = write!(&mut q, "${},", pl); - pl += 1; - } - q.pop(); - q.push(')'); + let (_, mut query) = (1..=num).fold((1, String::from(PREFIX)), |(idx, mut query), _| { + write!(query, "(${}::int,${}::int),", idx, idx + 1).unwrap(); + (idx + 2, query) + }); - let st = client.prepare_cached(&q, &[]).await?; - updates.push(st); - } + query.pop(); + + query.push_str(SUFFIX); + + query.into_boxed_str() +} + +pub async fn create() -> HandleResult { + let pool = Pool::builder(DB_URL).capacity(1).build()?; let shared = (Rand::default(), BytesMut::new()); + let updates = core::iter::once(Box::from("")) + .chain((1..=500).map(update_query)) + .collect::]>>(); + + { + let mut conn = pool.get().await?; + for update in updates.iter().skip(1) { + conn.prepare(update, &[]).await?; + } + } + Ok(Client { - client, + pool, #[cfg(not(feature = "pg-sync"))] shared: std::cell::RefCell::new(shared), #[cfg(feature = "pg-sync")] shared: std::sync::Mutex::new(shared), - fortune, - world, - updates: updates.into_boxed_slice(), + updates, }) } @@ -84,29 +81,26 @@ impl Client { } pub async fn get_world(&self) -> HandleResult { + let mut conn = self.pool.get().await?; + let stmt = conn.prepare(WORLD_SQL, WORLD_SQL_TYPES).await?; let id = self.shared().0.gen_id(); - self.client - .query_raw(&self.world, [id]) - .await? - .try_next() - .await? - .map(|row| World::new(row.get_raw(0), row.get_raw(1))) - .ok_or_else(|| "World does not exist".into()) + let mut res = conn.consume().query_raw(&stmt, [id])?; + let row = res.try_next().await?.ok_or_else(|| "World does not exist")?; + Ok(World::new(row.get_raw(0), row.get_raw(1))) } pub async fn get_worlds(&self, num: u16) -> HandleResult> { let len = num as usize; + let mut conn = self.pool.get().await?; + let stmt = conn.prepare(WORLD_SQL, WORLD_SQL_TYPES).await?; + let mut res = { let (ref mut rng, ref mut buf) = *self.shared(); - let mut pipe = Pipeline::with_capacity_from_buf(len, buf); - - (0..num).try_for_each(|_| pipe.query_raw(&self.world, [rng.gen_id()]))?; - - self.client.pipeline(pipe) - } - .await?; + (0..num).try_for_each(|_| pipe.query_raw(&stmt, [rng.gen_id()]))?; + conn.consume().pipeline(pipe)? + }; let mut worlds = Vec::with_capacity(len); @@ -122,37 +116,34 @@ impl Client { pub async fn update(&self, num: u16) -> HandleResult> { let len = num as usize; - let mut params = Vec::new(); - params.reserve(len * 3); + let update = self.updates.get(len).ok_or_else(|| "num out of bound")?; + + let mut conn = self.pool.get().await?; + let world_stmt = conn.prepare(WORLD_SQL, WORLD_SQL_TYPES).await?; + let update_stmt = conn.prepare(&update, &[]).await?; + + let mut params = Vec::with_capacity(len); let mut res = { let (ref mut rng, ref mut buf) = *self.shared(); - let mut pipe = Pipeline::with_capacity_from_buf(len + 1, buf); - (0..num).try_for_each(|_| { let w_id = rng.gen_id(); let r_id = rng.gen_id(); - params.extend([w_id, r_id]); - pipe.query_raw(&self.world, [w_id]) + params.push([w_id, r_id]); + pipe.query_raw(&world_stmt, [w_id]) })?; + pipe.query_raw(&update_stmt, sort_update_params(¶ms))?; + conn.consume().pipeline(pipe)? + }; - params.extend_from_within(..len); - - let st = self.updates.get(len).unwrap(); - pipe.query_raw(st, ¶ms)?; - - self.client.pipeline(pipe) - } - .await?; + let mut worlds = Vec::with_capacity(len); - let mut worlds = Vec::new(); - worlds.reserve(len); - let mut r_ids = params.into_iter().skip(1).step_by(2); + let mut r_ids = params.into_iter(); while let Some(mut item) = res.try_next().await? { while let Some(row) = item.try_next().await? { - let r_id = r_ids.next().unwrap(); + let r_id = r_ids.next().unwrap()[1]; worlds.push(World::new(row.get_raw(0), r_id)) } } @@ -164,12 +155,46 @@ impl Client { let mut items = Vec::with_capacity(32); items.push(Fortune::new(0, "Additional fortune added at request time.")); - let mut res = self.client.query_raw::<[i32; 0]>(&self.fortune, []).await?; + let mut conn = self.pool.get().await?; + let stmt = conn.prepare(FORTUNE_SQL, FORTUNE_SQL_TYPES).await?; + let mut res = conn.consume().query_raw::<[i32; 0]>(&stmt, [])?; + while let Some(row) = res.try_next().await? { items.push(Fortune::new(row.get_raw(0), row.get_raw::(1))); } + items.sort_by(|it, next| it.message.cmp(&next.message)); Ok(Fortunes::new(items)) } } + +fn sort_update_params(params: &Vec<[i32; 2]>) -> impl ExactSizeIterator { + let mut params = params.clone(); + params.sort_by(|a, b| a[0].cmp(&b[0])); + + struct ParamIter(I); + + impl Iterator for ParamIter + where + I: Iterator, + { + type Item = I::Item; + + #[inline] + fn next(&mut self) -> Option { + self.0.next() + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.0.size_hint() + } + } + + // impl depends on compiler optimization to flat Vec<[T]> to Vec when inferring + // it's size hint. possible to cause runtime panic. + impl ExactSizeIterator for ParamIter where I: Iterator {} + + ParamIter(params.into_iter().flatten()) +} diff --git a/frameworks/Rust/xitca-web/src/db_diesel.rs b/frameworks/Rust/xitca-web/src/db_diesel.rs index 79ba4c9a69a..2cd44344499 100644 --- a/frameworks/Rust/xitca-web/src/db_diesel.rs +++ b/frameworks/Rust/xitca-web/src/db_diesel.rs @@ -43,11 +43,7 @@ impl _Pool { let w_id = self.rng.lock().unwrap().gen_id(); let mut conn = self.pool.get()?; - world - .filter(id.eq(w_id)) - .load(&mut conn)? - .pop() - .ok_or_else(not_found) + world.filter(id.eq(w_id)).load(&mut conn)?.pop().ok_or_else(not_found) } pub fn get_worlds(&self, num: u16) -> HandleResult> { diff --git a/frameworks/Rust/xitca-web/src/main.rs b/frameworks/Rust/xitca-web/src/main.rs index 8405c986717..06c925bbb25 100755 --- a/frameworks/Rust/xitca-web/src/main.rs +++ b/frameworks/Rust/xitca-web/src/main.rs @@ -3,26 +3,20 @@ mod ser; mod util; use xitca_http::{ - body::Once, - bytes::Bytes, h1::RequestBody, - http::{ - self, - const_header_value::{TEXT, TEXT_HTML_UTF8}, - header::{CONTENT_TYPE, SERVER}, - IntoResponse, RequestExt, + http::{header::SERVER, StatusCode}, + util::service::{ + route::get, + router::{Router, RouterError}, }, - util::service::{route::get, router::Router}, HttpServiceBuilder, }; use xitca_service::{fn_service, Service, ServiceExt}; -use ser::{json_response, Message}; +use ser::{error_response, IntoResponse, Message, Request, Response}; use util::{context_mw, HandleResult, QueryParse, SERVER_HEADER_VALUE}; -type Request = http::Request>; -type Response = http::Response>; -type Ctx<'a> = util::Ctx<'a, Request>; +type Ctx<'a> = util::Ctx<'a, Request>; fn main() -> std::io::Result<()> { let service = Router::new() @@ -32,7 +26,7 @@ fn main() -> std::io::Result<()> { .insert("/fortunes", get(fn_service(fortunes))) .insert("/queries", get(fn_service(queries))) .insert("/updates", get(fn_service(updates))) - .enclosed_fn(middleware_fn) + .enclosed_fn(middleware) .enclosed(context_mw()) .enclosed(HttpServiceBuilder::h1().io_uring()); xitca_server::Builder::new() @@ -41,53 +35,54 @@ fn main() -> std::io::Result<()> { .wait() } -async fn middleware_fn(service: &S, req: Ctx<'_>) -> Result +async fn middleware(service: &S, req: Ctx<'_>) -> Result where - S: for<'c> Service, Response = Response, Error = E>, + S: for<'c> Service, Response = Response, Error = RouterError>, { - service.call(req).await.map(|mut res| { - res.headers_mut().insert(SERVER, SERVER_HEADER_VALUE); - res - }) + let mut res = service.call(req).await.unwrap_or_else(|e| match e { + RouterError::Match(_) => error_response(StatusCode::NOT_FOUND), + RouterError::NotAllowed(_) => error_response(StatusCode::METHOD_NOT_ALLOWED), + RouterError::Service(e) => { + println!("{e}"); + error_response(StatusCode::INTERNAL_SERVER_ERROR) + } + }); + res.headers_mut().insert(SERVER, SERVER_HEADER_VALUE); + Ok(res) } async fn plain_text(ctx: Ctx<'_>) -> HandleResult { - let (req, _) = ctx.into_parts(); - let mut res = req.into_response(const { Bytes::from_static(b"Hello, World!") }); - res.headers_mut().insert(CONTENT_TYPE, TEXT); - Ok(res) + ctx.into_parts().0.text_response() } async fn json(ctx: Ctx<'_>) -> HandleResult { let (req, state) = ctx.into_parts(); - json_response(req, &mut state.write_buf.borrow_mut(), &Message::new()) + req.json_response(state, &Message::new()) } async fn db(ctx: Ctx<'_>) -> HandleResult { let (req, state) = ctx.into_parts(); let world = state.client.get_world().await?; - json_response(req, &mut state.write_buf.borrow_mut(), &world) + req.json_response(state, &world) } async fn fortunes(ctx: Ctx<'_>) -> HandleResult { let (req, state) = ctx.into_parts(); use sailfish::TemplateOnce; let fortunes = state.client.tell_fortune().await?.render_once()?; - let mut res = req.into_response(Bytes::from(fortunes)); - res.headers_mut().insert(CONTENT_TYPE, TEXT_HTML_UTF8); - Ok(res) + req.html_response(fortunes) } async fn queries(ctx: Ctx<'_>) -> HandleResult { let (req, state) = ctx.into_parts(); let num = req.uri().query().parse_query(); let worlds = state.client.get_worlds(num).await?; - json_response(req, &mut state.write_buf.borrow_mut(), worlds.as_slice()) + req.json_response(state, &worlds) } async fn updates(ctx: Ctx<'_>) -> HandleResult { let (req, state) = ctx.into_parts(); let num = req.uri().query().parse_query(); let worlds = state.client.update(num).await?; - json_response(req, &mut state.write_buf.borrow_mut(), worlds.as_slice()) + req.json_response(state, &worlds) } diff --git a/frameworks/Rust/xitca-web/src/main_axum.rs b/frameworks/Rust/xitca-web/src/main_axum.rs index d15aaefdc6e..02fdfba8a20 100644 --- a/frameworks/Rust/xitca-web/src/main_axum.rs +++ b/frameworks/Rust/xitca-web/src/main_axum.rs @@ -99,9 +99,7 @@ mod tower_compat { HttpServiceBuilder, }; use xitca_io::net::io_uring::TcpStream; - use xitca_service::{ - fn_build, middleware::UncheckedReady, ready::ReadyService, Service, ServiceExt, - }; + use xitca_service::{fn_build, middleware::UncheckedReady, ready::ReadyService, Service, ServiceExt}; use xitca_web::service::tower_http_compat::{CompatReqBody, CompatResBody}; pub struct TowerHttp { @@ -112,17 +110,11 @@ mod tower_compat { impl TowerHttp { pub fn service( func: F, - ) -> impl Service< - Response = impl ReadyService + Service<(TcpStream, SocketAddr)>, - Error = impl fmt::Debug, - > + ) -> impl Service, Error = impl fmt::Debug> where F: Fn() -> Fut + Send + Sync + Clone, Fut: Future>, - S: tower::Service< - Request, ()>>, - Response = Response, - >, + S: tower::Service, ()>>, Response = Response>, S::Error: fmt::Debug, B: Body + Send + 'static, { @@ -142,18 +134,12 @@ mod tower_compat { impl Service>> for TowerHttp where - S: tower::Service< - Request, ()>>, - Response = Response, - >, + S: tower::Service, ()>>, Response = Response>, { type Response = Response>; type Error = S::Error; - async fn call( - &self, - req: Request>, - ) -> Result { + async fn call(&self, req: Request>) -> Result { let (parts, ext) = req.into_parts(); let req = Request::from_parts(parts, CompatReqBody::new(ext, ())); let fut = self.service.borrow_mut().call(req); diff --git a/frameworks/Rust/xitca-web/src/main_iou.rs b/frameworks/Rust/xitca-web/src/main_iou.rs index 8ca722f1fbe..af6f8424db0 100644 --- a/frameworks/Rust/xitca-web/src/main_iou.rs +++ b/frameworks/Rust/xitca-web/src/main_iou.rs @@ -12,31 +12,22 @@ use std::{convert::Infallible, fmt, future::poll_fn, io, pin::pin}; use futures_core::stream::Stream; use xitca_http::{ - body::Once, date::DateTimeService, h1::proto::context::Context, - http::{ - self, - const_header_value::{TEXT, TEXT_HTML_UTF8}, - header::{CONTENT_TYPE, SERVER}, - IntoResponse, RequestExt, StatusCode, - }, + http::{header::SERVER, StatusCode}, }; use xitca_io::{ - bytes::{Bytes, BytesMut}, + bytes::BytesMut, io_uring::BoundedBuf, net::{io_uring::TcpStream as IOUTcpStream, TcpStream}, }; use xitca_service::{fn_build, fn_service, middleware::UncheckedReady, Service, ServiceExt}; use self::{ - ser::{json_response, Message}, + ser::{error_response, IntoResponse, Message, Request, Response}, util::{context_mw, Ctx, QueryParse, SERVER_HEADER_VALUE}, }; -type Request = http::Request>; -type Response = http::Response>; - fn main() -> io::Result<()> { let service = fn_service(handler) .enclosed(context_mw()) @@ -53,47 +44,31 @@ fn main() -> io::Result<()> { .wait() } -async fn handler(ctx: Ctx<'_, Request>) -> Result { +async fn handler(ctx: Ctx<'_, Request<()>>) -> Result { let (req, state) = ctx.into_parts(); let mut res = match req.uri().path() { - "/plaintext" => { - let mut res = req.into_response(const { Bytes::from_static(b"Hello, World!") }); - res.headers_mut().insert(CONTENT_TYPE, TEXT); - res - } - "/json" => json_response(req, &mut state.write_buf.borrow_mut(), &Message::new()).unwrap(), + "/plaintext" => req.text_response().unwrap(), + "/json" => req.json_response(state, &Message::new()).unwrap(), "/db" => { let world = state.client.get_world().await.unwrap(); - json_response(req, &mut state.write_buf.borrow_mut(), &world).unwrap() + req.json_response(state, &world).unwrap() } "/queries" => { let num = req.uri().query().parse_query(); let worlds = state.client.get_worlds(num).await.unwrap(); - json_response(req, &mut state.write_buf.borrow_mut(), worlds.as_slice()).unwrap() + req.json_response(state, &worlds).unwrap() } "/updates" => { let num = req.uri().query().parse_query(); let worlds = state.client.update(num).await.unwrap(); - json_response(req, &mut state.write_buf.borrow_mut(), worlds.as_slice()).unwrap() + req.json_response(state, &worlds).unwrap() } "/fortunes" => { use sailfish::TemplateOnce; - let fortunes = state - .client - .tell_fortune() - .await - .unwrap() - .render_once() - .unwrap(); - let mut res = req.into_response(Bytes::from(fortunes)); - res.headers_mut().append(CONTENT_TYPE, TEXT_HTML_UTF8); - res - } - _ => { - let mut res = req.into_response(Bytes::new()); - *res.status_mut() = StatusCode::NOT_FOUND; - res + let fortunes = state.client.tell_fortune().await.unwrap().render_once().unwrap(); + req.html_response(fortunes).unwrap() } + _ => error_response(StatusCode::NOT_FOUND), }; res.headers_mut().insert(SERVER, SERVER_HEADER_VALUE); Ok(res) @@ -107,7 +82,7 @@ struct Http1IOU { // runner for http service. impl Service for Http1IOU where - S: Service, + S: Service, Response = Response>, S::Error: fmt::Debug, { type Response = (); @@ -138,10 +113,7 @@ where let (parts, body) = self.service.call(req).await.unwrap().into_parts(); let mut encoder = ctx.encode_head(parts, &body, &mut write_buf).unwrap(); let mut body = pin!(body); - let chunk = poll_fn(|cx| body.as_mut().poll_next(cx)) - .await - .unwrap() - .unwrap(); + let chunk = poll_fn(|cx| body.as_mut().poll_next(cx)).await.unwrap().unwrap(); encoder.encode(chunk, &mut write_buf); encoder.encode_eof(&mut write_buf); } diff --git a/frameworks/Rust/xitca-web/src/main_sync.rs b/frameworks/Rust/xitca-web/src/main_sync.rs index cf36166ac70..ae49ebf5827 100644 --- a/frameworks/Rust/xitca-web/src/main_sync.rs +++ b/frameworks/Rust/xitca-web/src/main_sync.rs @@ -51,17 +51,11 @@ fn fortunes(StateOwn(pool): StateOwn) -> HandleResult> { } #[route("/queries", method = get)] -fn queries( - Query(Num(num)): Query, - StateOwn(pool): StateOwn, -) -> HandleResult> { +fn queries(Query(Num(num)): Query, StateOwn(pool): StateOwn) -> HandleResult> { pool.get_worlds(num).map(Json) } #[route("/updates", method = get)] -fn updates( - Query(Num(num)): Query, - StateOwn(pool): StateOwn, -) -> HandleResult> { +fn updates(Query(Num(num)): Query, StateOwn(pool): StateOwn) -> HandleResult> { pool.update(num).map(Json) } diff --git a/frameworks/Rust/xitca-web/src/ser.rs b/frameworks/Rust/xitca-web/src/ser.rs index ca1c56caf70..e52f2f9c92c 100644 --- a/frameworks/Rust/xitca-web/src/ser.rs +++ b/frameworks/Rust/xitca-web/src/ser.rs @@ -5,11 +5,19 @@ use std::borrow::Cow; use serde::{ser::SerializeStruct, Deserialize, Deserializer, Serialize, Serializer}; use xitca_http::{ body::Once, - bytes::{BufMutWriter, Bytes, BytesMut}, - http::{const_header_value::JSON, header::CONTENT_TYPE, IntoResponse, Request, Response}, + bytes::{BufMutWriter, Bytes}, + http::{ + self, + const_header_value::{JSON, TEXT, TEXT_HTML_UTF8}, + header::CONTENT_TYPE, + IntoResponse as _, RequestExt, StatusCode, + }, }; -use crate::util::Error; +use crate::util::{Error, State}; + +const HELLO: &str = "Hello, World!"; +const HELLO_BYTES: &[u8] = HELLO.as_bytes(); #[derive(Clone)] pub struct Message { @@ -19,9 +27,7 @@ pub struct Message { impl Message { #[inline] pub const fn new() -> Self { - Self { - message: "Hello, World!", - } + Self { message: HELLO } } } @@ -128,8 +134,7 @@ impl<'de> Deserialize<'de> for Num { where V: MapAccess<'de>, { - map.next_key::()? - .ok_or_else(|| Error::missing_field("q"))?; + map.next_key::()?.ok_or_else(|| Error::missing_field("q"))?; let q = map.next_value::().unwrap_or(1); let q = cmp::min(500, cmp::max(1, q)); Ok(Num(q)) @@ -163,16 +168,44 @@ impl Serialize for World { } } -pub fn json_response( - req: Request, - buf: &mut BytesMut, - value: &S, -) -> Result>, Error> -where - S: ?Sized + Serialize, -{ - serde_json::to_writer(BufMutWriter(buf), value)?; - let mut res = req.into_response(buf.split().freeze()); - res.headers_mut().insert(CONTENT_TYPE, JSON); - Ok(res) +pub type Request = http::Request>; +pub type Response = http::Response>; + +pub trait IntoResponse: Sized { + fn json_response(self, state: &State, val: &impl Serialize) -> Result; + + fn text_response(self) -> Result; + + fn html_response(self, val: String) -> Result; +} + +impl IntoResponse for Request { + fn json_response(self, state: &State, val: &impl Serialize) -> Result { + let buf = &mut *state.write_buf.borrow_mut(); + serde_json::to_writer(BufMutWriter(buf), val)?; + let mut res = self.into_response(buf.split().freeze()); + res.headers_mut().insert(CONTENT_TYPE, JSON); + Ok(res) + } + + fn text_response(self) -> Result { + let mut res = self.into_response(const { Bytes::from_static(HELLO_BYTES) }); + res.headers_mut().insert(CONTENT_TYPE, TEXT); + Ok(res) + } + + fn html_response(self, val: String) -> Result { + let mut res = self.into_response(Bytes::from(val)); + res.headers_mut().insert(CONTENT_TYPE, TEXT_HTML_UTF8); + Ok(res) + } +} + +#[cold] +#[inline(never)] +pub fn error_response(status: StatusCode) -> Response { + http::Response::builder() + .status(status) + .body(Once::new(Bytes::new())) + .unwrap() } diff --git a/frameworks/Rust/xitca-web/src/util.rs b/frameworks/Rust/xitca-web/src/util.rs index dc0476a5d15..707279559ba 100755 --- a/frameworks/Rust/xitca-web/src/util.rs +++ b/frameworks/Rust/xitca-web/src/util.rs @@ -65,9 +65,7 @@ mod non_wasm { pub type Ctx<'a, Req> = Context<'a, Req, State>; - pub fn context_mw( - ) -> ContextBuilder Pin>>>>> - { + pub fn context_mw() -> ContextBuilder Pin>>>>> { ContextBuilder::new(|| { Box::pin(async { db::create().await.map(|client| State { From ced92062ee65608268915a8735de7ec427bcea54 Mon Sep 17 00:00:00 2001 From: Giovanni Barillari Date: Thu, 5 Sep 2024 22:03:30 +0200 Subject: [PATCH 108/204] [Python] Bump Granian to 1.6 (#9253) --- frameworks/Python/granian/requirements.txt | 2 +- frameworks/Python/granian/run.py | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/frameworks/Python/granian/requirements.txt b/frameworks/Python/granian/requirements.txt index 1a22a3ddfc2..90c02f2c8d4 100644 --- a/frameworks/Python/granian/requirements.txt +++ b/frameworks/Python/granian/requirements.txt @@ -1,4 +1,4 @@ asyncpg==0.29.0 -granian>=1.5.1,<1.6.0 +granian>=1.6.0,<1.7.0 jinja2==3.1.4 orjson==3.10.2 diff --git a/frameworks/Python/granian/run.py b/frameworks/Python/granian/run.py index 910b248422b..ef0724fad2f 100644 --- a/frameworks/Python/granian/run.py +++ b/frameworks/Python/granian/run.py @@ -7,9 +7,11 @@ if __name__ == '__main__': interface = sys.argv[1] threading_mode = sys.argv[2] + workers = multiprocessing.cpu_count() - #: split cores between the two loops - workers = round(multiprocessing.cpu_count() / 2) + if interface == "rsgi": + #: split cores between the two loops + workers = round(workers / 2) blocking_threads = None if interface == "wsgi": From 49663874d8b9bd42143fd20987a75dc90f8ed7f9 Mon Sep 17 00:00:00 2001 From: lospejos Date: Tue, 10 Sep 2024 23:10:44 +0300 Subject: [PATCH 109/204] Bumped version for Java, Jooby, Maven and other libraries/dependencies (#9182) * Bumped version for Java, Jooby, Maven and other libraries/dependencies * Bumped dependencies versions * Bumped dependencies versions * Bumped dependencies versions * Bumped dependencies versions * Fixed Resource_ issue * Bumped versions for Golang, Fiber and other dependencies * Bumped many deps versions, removed deprecated reuseBuffer() in Rocker * Bumped versions for Golang, Fiber and other dependencies --- frameworks/Go/fiber/fiber-prefork.dockerfile | 2 +- frameworks/Go/fiber/fiber.dockerfile | 2 +- frameworks/Go/fiber/src/go.mod | 30 ++++---- frameworks/Go/fiber/src/go.sum | 74 ++++++++----------- frameworks/Java/jooby/pom.xml | 12 +-- .../src/main/java/com/techempower/MvcApp.java | 2 +- frameworks/Kotlin/kooby/kooby.dockerfile | 2 +- frameworks/Kotlin/kooby/pom.xml | 20 ++--- .../Kotlin/kooby/src/main/kotlin/kooby/App.kt | 2 +- 9 files changed, 67 insertions(+), 79 deletions(-) diff --git a/frameworks/Go/fiber/fiber-prefork.dockerfile b/frameworks/Go/fiber/fiber-prefork.dockerfile index 85acc26ef6b..c741baca1b8 100644 --- a/frameworks/Go/fiber/fiber-prefork.dockerfile +++ b/frameworks/Go/fiber/fiber-prefork.dockerfile @@ -1,4 +1,4 @@ -FROM docker.io/golang:1.20 +FROM docker.io/golang:1.23 WORKDIR /fiber diff --git a/frameworks/Go/fiber/fiber.dockerfile b/frameworks/Go/fiber/fiber.dockerfile index 37f02a59405..23c8ab72ea7 100644 --- a/frameworks/Go/fiber/fiber.dockerfile +++ b/frameworks/Go/fiber/fiber.dockerfile @@ -1,4 +1,4 @@ -FROM docker.io/golang:1.20 +FROM docker.io/golang:1.23 WORKDIR /fiber diff --git a/frameworks/Go/fiber/src/go.mod b/frameworks/Go/fiber/src/go.mod index bb9b8bc5701..252db9355e6 100644 --- a/frameworks/Go/fiber/src/go.mod +++ b/frameworks/Go/fiber/src/go.mod @@ -1,30 +1,30 @@ module fiber/app -go 1.19 +go 1.23 require ( - github.com/goccy/go-json v0.10.0 + github.com/goccy/go-json v0.10.3 github.com/gofiber/fiber/v2 v2.52.5 - github.com/jackc/pgx/v5 v5.5.4 - github.com/valyala/quicktemplate v1.7.0 + github.com/jackc/pgx/v5 v5.6.0 + github.com/valyala/quicktemplate v1.8.0 ) require ( - github.com/andybalholm/brotli v1.0.5 // indirect - github.com/google/uuid v1.5.0 // indirect + github.com/andybalholm/brotli v1.1.0 // indirect + github.com/google/uuid v1.6.0 // indirect github.com/jackc/pgpassfile v1.0.0 // indirect - github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect + github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect github.com/jackc/puddle/v2 v2.2.1 // indirect - github.com/klauspost/compress v1.17.0 // indirect + github.com/klauspost/compress v1.17.9 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.20 // indirect - github.com/mattn/go-runewidth v0.0.15 // indirect - github.com/rivo/uniseg v0.2.0 // indirect + github.com/mattn/go-runewidth v0.0.16 // indirect + github.com/rivo/uniseg v0.4.7 // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect - github.com/valyala/fasthttp v1.51.0 // indirect + github.com/valyala/fasthttp v1.55.0 // indirect github.com/valyala/tcplisten v1.0.0 // indirect - golang.org/x/crypto v0.17.0 // indirect - golang.org/x/sync v0.1.0 // indirect - golang.org/x/sys v0.15.0 // indirect - golang.org/x/text v0.14.0 // indirect + golang.org/x/crypto v0.27.0 // indirect + golang.org/x/sync v0.8.0 // indirect + golang.org/x/sys v0.25.0 // indirect + golang.org/x/text v0.18.0 // indirect ) diff --git a/frameworks/Go/fiber/src/go.sum b/frameworks/Go/fiber/src/go.sum index 1414375d002..1cada1ee655 100644 --- a/frameworks/Go/fiber/src/go.sum +++ b/frameworks/Go/fiber/src/go.sum @@ -1,72 +1,60 @@ -github.com/andybalholm/brotli v1.0.2/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y= -github.com/andybalholm/brotli v1.0.3/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= -github.com/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/cCs= -github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= +github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1U3M= +github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= -github.com/goccy/go-json v0.10.0 h1:mXKd9Qw4NuzShiRlOXKews24ufknHO7gx30lsDyokKA= -github.com/goccy/go-json v0.10.0/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/goccy/go-json v0.10.3 h1:KZ5WoDbxAIgm2HNbYckL0se1fHD6rz5j4ywS6ebzDqA= +github.com/goccy/go-json v0.10.3/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= github.com/gofiber/fiber/v2 v2.52.5 h1:tWoP1MJQjGEe4GB5TUGOi7P2E0ZMMRx5ZTG4rT+yGMo= github.com/gofiber/fiber/v2 v2.52.5/go.mod h1:KEOE+cXMhXG0zHc9d8+E38hoX+ZN7bhOtgeF2oT6jrQ= -github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/google/uuid v1.5.0 h1:1p67kYwdtXjb0gL0BPiP1Av9wiZPo5A8z2cWkTZ+eyU= -github.com/google/uuid v1.5.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= -github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a h1:bbPeKD0xmW/Y25WS6cokEszi5g+S0QxI/d45PkRi7Nk= -github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= -github.com/jackc/pgx/v5 v5.5.4 h1:Xp2aQS8uXButQdnCMWNmvx6UysWQQC+u1EoizjguY+8= -github.com/jackc/pgx/v5 v5.5.4/go.mod h1:ez9gk+OAat140fv9ErkZDYFWmXLfV+++K0uAOiwgm1A= +github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo= +github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= +github.com/jackc/pgx/v5 v5.6.0 h1:SWJzexBzPL5jb0GEsrPMLIsi/3jOo7RHlzTjcAeDrPY= +github.com/jackc/pgx/v5 v5.6.0/go.mod h1:DNZ/vlrUnhWCoFGxHAG8U2ljioxukquj7utPDgtQdTw= github.com/jackc/puddle/v2 v2.2.1 h1:RhxXJtFG022u4ibrCSMSiu5aOq1i77R3OHKNJj77OAk= github.com/jackc/puddle/v2 v2.2.1/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4= -github.com/klauspost/compress v1.13.4/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg= -github.com/klauspost/compress v1.13.5/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= -github.com/klauspost/compress v1.17.0 h1:Rnbp4K9EjcDuVuHtd0dgA4qNuv9yKDYKK1ulpJwgrqM= -github.com/klauspost/compress v1.17.0/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= +github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA= +github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= -github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U= -github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc= +github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= +github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= +github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= -github.com/valyala/fasthttp v1.30.0/go.mod h1:2rsYD01CKFrjjsvFxx75KlEUNpWNBY9JWD3K/7o2Cus= -github.com/valyala/fasthttp v1.51.0 h1:8b30A5JlZ6C7AS81RsWjYMQmrZG6feChmgAolCl1SqA= -github.com/valyala/fasthttp v1.51.0/go.mod h1:oI2XroL+lI7vdXyYoQk03bXBThfFl2cVdIA3Xl7cH8g= -github.com/valyala/quicktemplate v1.7.0 h1:LUPTJmlVcb46OOUY3IeD9DojFpAVbsG+5WFTcjMJzCM= -github.com/valyala/quicktemplate v1.7.0/go.mod h1:sqKJnoaOF88V07vkO+9FL8fb9uZg/VPSJnLYn+LmLk8= +github.com/valyala/fasthttp v1.55.0 h1:Zkefzgt6a7+bVKHnu/YaYSOPfNYNisSVBo/unVCf8k8= +github.com/valyala/fasthttp v1.55.0/go.mod h1:NkY9JtkrpPKmgwV3HTaS2HWaJss9RSIsRVfcxxoHiOM= +github.com/valyala/quicktemplate v1.8.0 h1:zU0tjbIqTRgKQzFY1L42zq0qR3eh4WoQQdIdqCysW5k= +github.com/valyala/quicktemplate v1.8.0/go.mod h1:qIqW8/igXt8fdrUln5kOSb+KWMaJ4Y8QUsfd1k6L2jM= github.com/valyala/tcplisten v1.0.0 h1:rBHj/Xf+E1tRGZyWIWwJDiRY0zc1Js+CV5DqwacVSA8= github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc= -golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= -golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k= -golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= -golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210510120150-4163338589ed/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= -golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/crypto v0.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A= +golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70= +golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= +golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= -golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= -golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34= +golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224= +golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/frameworks/Java/jooby/pom.xml b/frameworks/Java/jooby/pom.xml index bd6ce1a1c68..99170fb8cfe 100644 --- a/frameworks/Java/jooby/pom.xml +++ b/frameworks/Java/jooby/pom.xml @@ -11,10 +11,10 @@ jooby - 3.2.4 - 4.1.111.Final + 3.2.9 + 4.1.112.Final 2.0.2 - 42.7.3 + 42.7.4 UTF-8 21 21 @@ -72,7 +72,7 @@ org.codehaus.mojo build-helper-maven-plugin - 3.5.0 + 3.6.0 add-source @@ -110,7 +110,7 @@ org.apache.maven.plugins maven-compiler-plugin - 3.12.1 + 3.13.0 @@ -130,7 +130,7 @@ org.apache.maven.plugins maven-shade-plugin - 3.5.2 + 3.6.0 uber-jar diff --git a/frameworks/Java/jooby/src/main/java/com/techempower/MvcApp.java b/frameworks/Java/jooby/src/main/java/com/techempower/MvcApp.java index 68d09e0a472..ad40629a635 100644 --- a/frameworks/Java/jooby/src/main/java/com/techempower/MvcApp.java +++ b/frameworks/Java/jooby/src/main/java/com/techempower/MvcApp.java @@ -17,7 +17,7 @@ public static void main(String[] args) { /** Template engine: */ app.install(new RockerModule()); - app.mvc(new Resource(app.require(DataSource.class))); + app.mvc(new Resource_(app.require(DataSource.class))); }); } } diff --git a/frameworks/Kotlin/kooby/kooby.dockerfile b/frameworks/Kotlin/kooby/kooby.dockerfile index 56c278c467a..678fc57b8d4 100644 --- a/frameworks/Kotlin/kooby/kooby.dockerfile +++ b/frameworks/Kotlin/kooby/kooby.dockerfile @@ -1,4 +1,4 @@ -FROM maven:3.9.0-eclipse-temurin-17 +FROM maven:3.9.9-eclipse-temurin-22-alpine WORKDIR /kooby COPY pom.xml pom.xml COPY src src diff --git a/frameworks/Kotlin/kooby/pom.xml b/frameworks/Kotlin/kooby/pom.xml index 9ae92257022..4ff8df958da 100644 --- a/frameworks/Kotlin/kooby/pom.xml +++ b/frameworks/Kotlin/kooby/pom.xml @@ -12,12 +12,12 @@ kooby: jooby+kotlin - 3.0.5 - 42.7.2 + 3.3.0 + 42.7.4 UTF-8 - 17 - 17 - 1.8.21 + 22 + 22 + 2.0.20 kooby.AppKt @@ -52,7 +52,7 @@ com.mysql mysql-connector-j - 8.2.0 + 9.0.0 @@ -77,7 +77,7 @@ com.fizzed rocker-maven-plugin - 1.3.0 + 1.4.0 generate-rocker-templates @@ -98,7 +98,7 @@ kotlin-maven-plugin ${kotlin.version} - 17 + 22 @@ -127,7 +127,7 @@ org.apache.maven.plugins maven-compiler-plugin - 3.11.0 + 3.13.0 @@ -159,7 +159,7 @@ org.apache.maven.plugins maven-shade-plugin - 3.2.4 + 3.6.0 uber-jar diff --git a/frameworks/Kotlin/kooby/src/main/kotlin/kooby/App.kt b/frameworks/Kotlin/kooby/src/main/kotlin/kooby/App.kt index edc43137b1b..958991e29d3 100644 --- a/frameworks/Kotlin/kooby/src/main/kotlin/kooby/App.kt +++ b/frameworks/Kotlin/kooby/src/main/kotlin/kooby/App.kt @@ -33,7 +33,7 @@ fun main(args: Array) { runApp(args, EVENT_LOOP) { /** Template engine: */ - install(RockerModule().reuseBuffer(true)) + install(RockerModule()) /** JSON: */ install(JacksonModule()) From ba6923509494dc5ed1d1b48d2f5e8f79c9bc0510 Mon Sep 17 00:00:00 2001 From: Dragos Varovici Date: Tue, 10 Sep 2024 14:11:29 -0600 Subject: [PATCH 110/204] Zap upgraded to 0.8 (#9254) * Zap upgraded to 0.8 * Zap 0.8 fixes --- frameworks/Zig/zap/build.zig | 42 +++++++-------- frameworks/Zig/zap/build.zig.zon | 34 +++++------- frameworks/Zig/zap/run.sh | 2 +- frameworks/Zig/zap/src/endpoints.zig | 33 ++++++------ frameworks/Zig/zap/src/main.zig | 11 ++-- frameworks/Zig/zap/src/middleware.zig | 10 ++-- frameworks/Zig/zap/src/pool.zig | 77 +++++++++++++++------------ frameworks/Zig/zap/zap.dockerfile | 46 ++++++++-------- 8 files changed, 128 insertions(+), 127 deletions(-) diff --git a/frameworks/Zig/zap/build.zig b/frameworks/Zig/zap/build.zig index 70c740351a1..762284c2acb 100644 --- a/frameworks/Zig/zap/build.zig +++ b/frameworks/Zig/zap/build.zig @@ -1,9 +1,12 @@ const std = @import("std"); +const ModuleMap = std.StringArrayHashMap(*std.Build.Module); +var gpa = std.heap.GeneralPurposeAllocator(.{}){}; +const allocator = gpa.allocator(); // Although this function looks imperative, note that its job is to // declaratively construct a build graph that will be executed by an external // runner. -pub fn build(b: *std.Build) void { +pub fn build(b: *std.Build) !void { // Standard target options allows the person running `zig build` to choose // what target to build for. Here we do not override the defaults, which // means any target is allowed, and the default is native. Other options @@ -15,41 +18,38 @@ pub fn build(b: *std.Build) void { // set a preferred release mode, allowing the user to decide how to optimize. const optimize = b.standardOptimizeOption(.{}); + const dep_opts = .{ .target = target, .optimize = optimize }; + const exe = b.addExecutable(.{ .name = "zap", // In this case the main source file is merely a path, however, in more // complicated build scripts, this could be a generated file. - .root_source_file = .{ .path = "src/main.zig" }, + .root_source_file = b.path("src/main.zig"), .target = target, .optimize = optimize, }); - //exe.addPackagePath("random", "src/random.zig"); - const zap = b.dependency("zap", .{ .target = target, .optimize = optimize, .openssl = false, // set to true to enable TLS support }); - exe.addModule("zap", zap.module("zap")); - const pg = b.dependency("pg", .{ - .target = target, - .optimize = optimize, - }); - exe.addModule("pg", pg.module("pg")); + var modules = ModuleMap.init(allocator); + defer modules.deinit(); - const dig = b.dependency("dig", .{ - .target = target, - .optimize = optimize, - }); - exe.addModule("dns", dig.module("dns")); + const zap_module = b.dependency("zap", dep_opts).module("zap"); + const pg_module = b.dependency("pg", dep_opts).module("pg"); + const dig_module = b.dependency("dig", dep_opts).module("dns"); + + try modules.put("zap", zap_module); + try modules.put("pg", pg_module); + try modules.put("dig", dig_module); - // const mustache = b.dependency("mustache", .{ - // .target = target, - // .optimize = optimize, - // }); - // exe.addModule("mustache", mustache.module("mustache")); + // // Expose this as a module that others can import + exe.root_module.addImport("zap", zap_module); + exe.root_module.addImport("pg", pg_module); + exe.root_module.addImport("dig", dig_module); exe.linkLibrary(zap.artifact("facil.io")); @@ -84,7 +84,7 @@ pub fn build(b: *std.Build) void { // Creates a step for unit testing. This only builds the test executable // but does not run it. const unit_tests = b.addTest(.{ - .root_source_file = .{ .path = "src/main.zig" }, + .root_source_file = b.path("src/main.zig"), .target = target, .optimize = optimize, }); diff --git a/frameworks/Zig/zap/build.zig.zon b/frameworks/Zig/zap/build.zig.zon index 3abfe719e55..871e73b7f76 100644 --- a/frameworks/Zig/zap/build.zig.zon +++ b/frameworks/Zig/zap/build.zig.zon @@ -1,21 +1,13 @@ -.{ - .name = "Zap testing", - .version = "0.1.0", - - .dependencies = .{ - // zap v0.5.1 - .zap = .{ - .url = "https://github.com/zigzap/zap/archive/refs/tags/v0.5.1.tar.gz", - .hash = "1220d4802fb09d4e99c0e7265f90d6f3cfdc3e5e31c1b05f0924ee2dd26d9d6dbbf4", - }, - .pg = .{ - .url = "https://github.com/karlseguin/pg.zig/archive/f3f4a0b3b9996bfb1bf9bd0bdd0d73b36e915a86.tar.gz", - .hash = "1220337202642ee66408a35f254549f22cf3a096c6fa6c28e6f87a0161d5a6c0f4ab" - }, - .dig = .{ - .url = "https://github.com/lun-4/zigdig/archive/2ec407ec3c7f347e747717977958e9ba339eb82f.tar.gz", - .hash = "1220dfdb3089dfe9a4e4bc1226fcff08d91d0c0853f287d98d8b81270da251790331" - }, - - } -} \ No newline at end of file +.{ .name = "Zap testing", .version = "0.1.1", .paths = .{ + "build.zig", + "build.zig.zon", + "src", +}, .dependencies = .{ + .zap = .{ + .url = "https://github.com/zigzap/zap/archive/refs/tags/v0.8.0.tar.gz", + .hash = "12209936c3333b53b53edcf453b1670babb9ae8c2197b1ca627c01e72670e20c1a21", + }, + .pg = .{ .url = "https://github.com/karlseguin/pg.zig/archive/239a4468163a49d8c0d03285632eabe96003e9e2.tar.gz", + .hash = "1220a1d7e51e2fa45e547c76a9e099c09d06e14b0b9bfc6baa89367f56f1ded399a0" }, + .dig = .{ .url = "https://github.com/lun-4/zigdig/archive/a54c85c26aa83c64ee81e3ee1818890be5cbed0b.tar.gz", .hash = "1220f078ab62d1328339504f9122dc4d241be30ada451628d78b8a3bf5bb9be1dcba" }, +} } diff --git a/frameworks/Zig/zap/run.sh b/frameworks/Zig/zap/run.sh index 95c2266e8bd..b4698a15de1 100644 --- a/frameworks/Zig/zap/run.sh +++ b/frameworks/Zig/zap/run.sh @@ -1,3 +1,3 @@ -echo "Waiting for ZAP to start..." +echo "Waiting for ZAP framework to start..." zap \ No newline at end of file diff --git a/frameworks/Zig/zap/src/endpoints.zig b/frameworks/Zig/zap/src/endpoints.zig index aeeffbf4e0a..3492e686591 100644 --- a/frameworks/Zig/zap/src/endpoints.zig +++ b/frameworks/Zig/zap/src/endpoints.zig @@ -64,27 +64,27 @@ pub const FortunesEndpoint = struct { defer conn.release(); var rows = try conn.query("SELECT id, message FROM Fortune", .{}); - rows.deinit(); + defer rows.deinit(); var fortunes = std.ArrayList(Fortune).init(middleware.SharedAllocator.getAllocator()); defer fortunes.deinit(); while (try rows.next()) |row| { - var fortune = Fortune{ .id = row.get(i32, 0), .message = row.get([]const u8, 1) }; - _ = try fortunes.append(fortune); + const fortune = Fortune{ .id = row.get(i32, 0), .message = row.get([]const u8, 1) }; + try fortunes.append(fortune); } - var fortune = Fortune{ .id = 0, .message = "Additional fortune added at request time." }; - _ = try fortunes.append(fortune); + const fortune = Fortune{ .id = 0, .message = "Additional fortune added at request time." }; + try fortunes.append(fortune); - var fortunes_slice = try fortunes.toOwnedSlice(); + const fortunes_slice = try fortunes.toOwnedSlice(); std.mem.sort(Fortune, fortunes_slice, {}, cmpFortuneByMessage); return fortunes_slice; } fn getFortunesHtml(self: *Self, pool: *pg.Pool) ![]const u8 { - var fortunes = try getFortunes(pool); + const fortunes = try getFortunes(pool); self.mutex.lock(); const ret = self.mustache.build(.{ .fortunes = fortunes }); @@ -95,7 +95,7 @@ pub const FortunesEndpoint = struct { // std.debug.print("mustache output {s}\n", .{raw}); - var html = try deescapeHtml(raw); + const html = try deescapeHtml(raw); // std.debug.print("html output {s}\n", .{html}); @@ -103,7 +103,7 @@ pub const FortunesEndpoint = struct { } pub fn get(ep: *zap.Endpoint, req: zap.Request) void { - const self = @fieldParentPtr(Self, "ep", ep); + const self: *FortunesEndpoint = @fieldParentPtr("ep", ep); if (!checkPath(ep, req)) return; @@ -118,7 +118,7 @@ pub const FortunesEndpoint = struct { } } - var fortunes_html = getFortunesHtml(self, pool) catch return; + const fortunes_html = getFortunesHtml(self, pool) catch return; req.sendBody(fortunes_html) catch return; @@ -146,7 +146,7 @@ pub const DbEndpoint = struct { } pub fn get(ep: *zap.Endpoint, req: zap.Request) void { - const self = @fieldParentPtr(Self, "ep", ep); + const self: *DbEndpoint = @fieldParentPtr("ep", ep); if (!checkPath(ep, req)) return; @@ -177,14 +177,13 @@ pub const DbEndpoint = struct { var conn = pool.acquire() catch return; defer conn.release(); - var row_result = conn.row("SELECT id, randomNumber FROM World WHERE id = $1", .{random_number}) catch |err| { + const row_result = conn.row("SELECT id, randomNumber FROM World WHERE id = $1", .{random_number}) catch |err| { std.debug.print("Error querying database: {}\n", .{err}); return; }; var row = row_result.?; - defer row.deinit(); - var world = World{ .id = row.get(i32, 0), .randomNumber = row.get(i32, 1) }; + const world = World{ .id = row.get(i32, 0), .randomNumber = row.get(i32, 1) }; var buf: [100]u8 = undefined; var json_to_send: []const u8 = undefined; @@ -218,7 +217,7 @@ pub const PlaintextEndpoint = struct { } pub fn get(ep: *zap.Endpoint, req: zap.Request) void { - const self = @fieldParentPtr(Self, "ep", ep); + const self: *PlaintextEndpoint = @fieldParentPtr("ep", ep); _ = self; if (!checkPath(ep, req)) return; @@ -248,14 +247,14 @@ pub const JsonEndpoint = struct { } pub fn get(ep: *zap.Endpoint, req: zap.Request) void { - const self = @fieldParentPtr(Self, "ep", ep); + const self: *JsonEndpoint = @fieldParentPtr("ep", ep); _ = self; if (!checkPath(ep, req)) return; req.setContentType(.JSON) catch return; - var message = Message{ .message = "Hello, World!" }; + const message = Message{ .message = "Hello, World!" }; var buf: [100]u8 = undefined; var json_to_send: []const u8 = undefined; diff --git a/frameworks/Zig/zap/src/main.zig b/frameworks/Zig/zap/src/main.zig index 489fb5d5b7e..0c66a7639bb 100644 --- a/frameworks/Zig/zap/src/main.zig +++ b/frameworks/Zig/zap/src/main.zig @@ -21,16 +21,12 @@ pub fn main() !void { .child_allocator = gpa.allocator(), }; - var allocator = tsa.allocator(); + const allocator = tsa.allocator(); var pg_pool = try pool.initPool(allocator); defer pg_pool.deinit(); - var rnd = std.rand.DefaultPrng.init(blk: { - var seed: u64 = undefined; - try std.os.getrandom(std.mem.asBytes(&seed)); - break :blk seed; - }); + var prng = std.rand.DefaultPrng.init(@as(u64, @bitCast(std.time.milliTimestamp()))); middleware.SharedAllocator.init(allocator); @@ -66,7 +62,7 @@ pub fn main() !void { ); var headerHandler = middleware.HeaderMiddleWare.init(dbEndpointHandler.getHandler()); - var prngHandler = middleware.PrngMiddleWare.init(headerHandler.getHandler(), &rnd); + var prngHandler = middleware.RandomMiddleWare.init(headerHandler.getHandler(), &prng); var pgHandler = middleware.PgMiddleWare.init(prngHandler.getHandler(), pg_pool); var listener = try zap.Middleware.Listener(middleware.Context).init( @@ -92,4 +88,3 @@ pub fn main() !void { .workers = 1, }); } - diff --git a/frameworks/Zig/zap/src/middleware.zig b/frameworks/Zig/zap/src/middleware.zig index 20c01b7ffde..99fb9255c0c 100644 --- a/frameworks/Zig/zap/src/middleware.zig +++ b/frameworks/Zig/zap/src/middleware.zig @@ -22,7 +22,7 @@ pub const SharedAllocator = struct { // create a combined context struct pub const Context = struct { - prng: ?PrngMiddleWare.Prng = null, + prng: ?RandomMiddleWare.Prng = null, pg: ?PgMiddleWare.Pg = null, }; @@ -47,7 +47,7 @@ pub const HeaderMiddleWare = struct { // note that the first parameter is of type *Handler, not *Self !!! pub fn onRequest(handler: *Handler, req: zap.Request, context: *Context) bool { // this is how we would get our self pointer - var self = @fieldParentPtr(Self, "handler", handler); + const self: *Self = @fieldParentPtr("handler", handler); _ = self; req.setHeader("Server", "Zap") catch return false; @@ -57,7 +57,7 @@ pub const HeaderMiddleWare = struct { } }; -pub const PrngMiddleWare = struct { +pub const RandomMiddleWare = struct { handler: Handler, rnd: *std.rand.DefaultPrng, @@ -83,7 +83,7 @@ pub const PrngMiddleWare = struct { pub fn onRequest(handler: *Handler, req: zap.Request, context: *Context) bool { // this is how we would get our self pointer - var self = @fieldParentPtr(Self, "handler", handler); + const self: *RandomMiddleWare = @fieldParentPtr("handler", handler); context.prng = Prng{ .rnd = self.rnd }; @@ -118,7 +118,7 @@ pub const PgMiddleWare = struct { pub fn onRequest(handler: *Handler, req: zap.Request, context: *Context) bool { // this is how we would get our self pointer - var self = @fieldParentPtr(Self, "handler", handler); + const self: *Self = @fieldParentPtr("handler", handler); // do our work: fill in the user field of the context context.pg = Pg{ .pool = self.pool }; diff --git a/frameworks/Zig/zap/src/pool.zig b/frameworks/Zig/zap/src/pool.zig index 7241780a464..84df32104b0 100644 --- a/frameworks/Zig/zap/src/pool.zig +++ b/frameworks/Zig/zap/src/pool.zig @@ -1,7 +1,7 @@ const std = @import("std"); -const pg = @import("pg"); const regex = @import("regex"); -const dns = @import("dns"); +const dns = @import("dig"); +const pg = @import("pg"); const Allocator = std.mem.Allocator; const Pool = pg.Pool; @@ -9,31 +9,22 @@ const ArrayList = std.ArrayList; const Regex = regex.Regex; pub fn initPool(allocator: Allocator) !*pg.Pool { - const info = try parsePostgresConnStr(); - std.debug.print("Cconnection info: {s}:{s}@{s}:{d}/{s}\n", .{ info.username, info.password, info.hostname, info.port, info.database }); - - const hostname = std.os.getenv("PG_HOST") orelse "localhost"; - var addresses = try dns.helpers.getAddressList(hostname, allocator); - defer addresses.deinit(); - - var hostAddress = std.net.Address.parseIp("127.0.0.1", 0) catch unreachable; - - for (addresses.addrs) |address| { - hostAddress = address; - } - - std.debug.print("tfb hostname {}\n", .{hostAddress.in}); - - const host = try addressAsString(hostAddress); - - var pg_pool = try Pool.init(allocator, .{ .size = 28, .connect = .{ - .port = info.port, - .host = host, - }, .auth = .{ - .username = info.username, - .database = info.database, - .password = info.password, - }, .timeout = 10_000,}); + const info = try parsePostgresConnStr(allocator); + std.debug.print("Connection: {s}:{s}@{s}:{d}/{s}\n", .{ info.username, info.password, info.hostname, info.port, info.database }); + + const pg_pool = try Pool.init(allocator, .{ + .size = 28, + .connect = .{ + .port = info.port, + .host = info.hostname, + }, + .auth = .{ + .username = info.username, + .database = info.database, + .password = info.password, + }, + .timeout = 10_000, + }); return pg_pool; } @@ -67,12 +58,32 @@ fn addressAsString(address: std.net.Address) ![]const u8 { return output; } -fn parsePostgresConnStr() !ConnectionInfo { +fn parsePostgresConnStr(allocator: Allocator) !ConnectionInfo { + const pg_port = try getEnvVar(allocator, "PG_PORT", "5432"); + std.debug.print("tfb port {s}\n", .{pg_port}); + var port = try std.fmt.parseInt(u16, pg_port, 0); + + if (port == 0) { + port = 5432; + } + return ConnectionInfo{ - .username = std.os.getenv("PG_USER") orelse "benchmarkdbuser", - .password = std.os.getenv("PG_PASS") orelse "benchmarkdbpass", - .hostname = std.os.getenv("PG_HOST") orelse "localhost", // , - .port = try std.fmt.parseInt(u16, std.os.getenv("PG_PORT") orelse "5432", 0), - .database = std.os.getenv("PG_DB") orelse "hello_world", + .username = try getEnvVar(allocator, "PG_USER", "benchmarkdbuser"), + .password = try getEnvVar(allocator, "PG_PASS", "benchmarkdbpass"), + .hostname = try getEnvVar(allocator, "PG_HOST", "localhost"), + .port = port, + .database = try getEnvVar(allocator, "PG_DB", "hello_world"), }; } + +fn getEnvVar(allocator: Allocator, name: []const u8, default: []const u8) ![]const u8 { + const env_var = std.process.getEnvVarOwned(allocator, name) catch |err| switch (err) { + error.EnvironmentVariableNotFound => return default, + error.OutOfMemory => return err, + error.InvalidWtf8 => return err, + }; + + if (env_var.len == 0) return default; + + return env_var; +} diff --git a/frameworks/Zig/zap/zap.dockerfile b/frameworks/Zig/zap/zap.dockerfile index 580f037bcef..9aa8a4109ae 100644 --- a/frameworks/Zig/zap/zap.dockerfile +++ b/frameworks/Zig/zap/zap.dockerfile @@ -1,42 +1,46 @@ -#FROM ziglang/static-base:llvm15-aarch64-3 as build -FROM buddyspencer/ziglang:0.11.0-r3 as build +FROM fedora:40 AS build WORKDIR /zap +ENV PG_USER=benchmarkdbuser +ENV PG_PASS=benchmarkdbpass +ENV PG_DB=hello_world +ENV PG_HOST=tfb-database +ENV PG_PORT=5432 + COPY src src +COPY run.sh run.sh COPY build.zig.zon build.zig.zon COPY build.zig build.zig -RUN apk update -RUN apk add yaml-dev sqlite-dev -RUN apk add bind-tools -RUN apk add --no-cache bash -RUN dig +short localhost | head -n 1 -RUN zig build -Doptimize=ReleaseFast --prefix-exe-dir /usr/bin +RUN dnf install -y zig RUN zig version -RUN ls +# RUN zig build -Doptimize=ReleaseFast +RUN zig build +RUN cp /zap/zig-out/bin/zap /usr/local/bin EXPOSE 3000 CMD ["sh", "run.sh"] -FROM alpine:3.19 +# FROM alpine:3.19 -WORKDIR /zap +# WORKDIR /zap -ENV PG_USER=benchmarkdbuser -ENV PG_PASS=benchmarkdbpass -ENV PG_DB=hello_world -ENV PG_HOST=tfb-database -ENV PG_PORT=5432 +# ENV PG_USER=benchmarkdbuser +# ENV PG_PASS=benchmarkdbpass +# ENV PG_DB=hello_world +# ENV PG_HOST=tfb-database +# ENV PG_PORT=5432 -COPY run.sh run.sh +# RUN apk update +# RUN apk add libc6-compat -RUN apk update +# COPY run.sh run.sh -COPY --from=build /usr/bin/zap /usr/bin/zap +# COPY --from=build /zap/zig-out/bin/zap /usr/local/bin -EXPOSE 3000 +# EXPOSE 3000 -CMD ["sh", "run.sh"] \ No newline at end of file +# CMD ["sh", "run.sh"] \ No newline at end of file From f03d5ee8221a3c68ab9efe7dd2f4f56c29c73320 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 10 Sep 2024 20:11:35 +0000 Subject: [PATCH 111/204] Bump body-parser from 1.19.0 to 1.20.3 in /frameworks/JavaScript/express Bumps [body-parser](https://github.com/expressjs/body-parser) from 1.19.0 to 1.20.3. - [Release notes](https://github.com/expressjs/body-parser/releases) - [Changelog](https://github.com/expressjs/body-parser/blob/master/HISTORY.md) - [Commits](https://github.com/expressjs/body-parser/compare/1.19.0...1.20.3) --- updated-dependencies: - dependency-name: body-parser dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- frameworks/JavaScript/express/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frameworks/JavaScript/express/package.json b/frameworks/JavaScript/express/package.json index 32ea58ae528..09723c74dd8 100644 --- a/frameworks/JavaScript/express/package.json +++ b/frameworks/JavaScript/express/package.json @@ -3,7 +3,7 @@ "version": "0.0.1", "private": true, "dependencies": { - "body-parser": "1.19.0", + "body-parser": "1.20.3", "dateformat": "3.0.3", "escape-html": "1.0.3", "express": "4.18.2", From 844094b11d96033697b39bad81c791c88021fe17 Mon Sep 17 00:00:00 2001 From: Petrik de Heus Date: Thu, 12 Sep 2024 18:06:27 +0200 Subject: [PATCH 112/204] [rails] Delete remaining unused middleware (#9259) The following middleware is unused for the benchmark: - Callbacks - Rack::TempfileReaper The following middleware is already disabled in production by default, so they don't need to be deleted: - ActionDispatch::HostAuthorization - ActionDispatch::Static The remaining middleware are: - ActiveSupport::Cache::Strategy::LocalCache::Middleware - Hello::Application.routes Also sort the middleware. The middleware can be checked using the following command: SECRET_KEY_BASE_DUMMY=1 RAILS_ENV=production_mysql bin/rails middleware --- frameworks/Ruby/rails/config/application.rb | 31 +++++++++---------- .../rails/config/environments/production.rb | 3 +- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/frameworks/Ruby/rails/config/application.rb b/frameworks/Ruby/rails/config/application.rb index 7e3e1d4af56..75a12720345 100644 --- a/frameworks/Ruby/rails/config/application.rb +++ b/frameworks/Ruby/rails/config/application.rb @@ -30,27 +30,26 @@ class Application < Rails::Application config.action_dispatch.default_headers.merge!('Server' => 'WebServer') - config.middleware.delete ActionDispatch::HostAuthorization - config.middleware.delete Rack::Sendfile - config.middleware.delete ActionDispatch::Static + config.middleware.delete ActionDispatch::Callbacks + config.middleware.delete ActionDispatch::ContentSecurityPolicy::Middleware + config.middleware.delete ActionDispatch::Cookies + config.middleware.delete ActionDispatch::DebugExceptions config.middleware.delete ActionDispatch::Executor - config.middleware.delete Rack::Runtime - config.middleware.delete Rack::MethodOverride - config.middleware.delete ActionDispatch::RequestId + config.middleware.delete ActionDispatch::Flash + config.middleware.delete ActionDispatch::PermissionsPolicy::Middleware + config.middleware.delete ActionDispatch::Reloader config.middleware.delete ActionDispatch::RemoteIp - config.middleware.delete Rails::Rack::Logger + config.middleware.delete ActionDispatch::RequestId + config.middleware.delete ActionDispatch::Session::CookieStore config.middleware.delete ActionDispatch::ShowExceptions - config.middleware.delete ActionDispatch::DebugExceptions - config.middleware.delete ActionDispatch::ActionableExceptions - config.middleware.delete ActionDispatch::Reloader config.middleware.delete ActiveRecord::Migration::CheckPending - config.middleware.delete ActionDispatch::Cookies - config.middleware.delete ActionDispatch::Session::CookieStore - config.middleware.delete ActionDispatch::Flash - config.middleware.delete ActionDispatch::ContentSecurityPolicy::Middleware - config.middleware.delete ActionDispatch::PermissionsPolicy::Middleware - config.middleware.delete Rack::Head config.middleware.delete Rack::ConditionalGet config.middleware.delete Rack::ETag + config.middleware.delete Rack::Head + config.middleware.delete Rack::MethodOverride + config.middleware.delete Rack::Runtime + config.middleware.delete Rack::Sendfile + config.middleware.delete Rack::TempfileReaper + config.middleware.delete Rails::Rack::Logger end end diff --git a/frameworks/Ruby/rails/config/environments/production.rb b/frameworks/Ruby/rails/config/environments/production.rb index f9de0f173d6..45b097c9f04 100644 --- a/frameworks/Ruby/rails/config/environments/production.rb +++ b/frameworks/Ruby/rails/config/environments/production.rb @@ -21,7 +21,8 @@ # config.require_master_key = true # Disable serving static files from `public/`, relying on NGINX/Apache to do so instead. - # config.public_file_server.enabled = false + # This disables the ActionDispatch::Static middleware. + config.public_file_server.enabled = false # Enable serving of images, stylesheets, and JavaScripts from an asset server. # config.asset_host = "http://assets.example.com" From a329357a317652fad2f7ac2c0bde2e384264fceb Mon Sep 17 00:00:00 2001 From: Redkale Date: Fri, 13 Sep 2024 00:06:42 +0800 Subject: [PATCH 113/204] Update maven:3.9.6 (#9257) * Update maven:3.9.6 * Update graalvm:22.0.2 * Update graalvm-ce:22.3.3 * Update native-image-community:22.0.2 * Update jdk-community:22.0.2 * Update graalvm-ce:ol9 * Update graalvm-ce:ol9 * Update config * Update config * Update config * Update config * Update FortuneRender * Update Redkale-2.8.0 --- frameworks/Java/redkale/BenchmarkService.java | 5 +++ frameworks/Java/redkale/conf/application.xml | 8 ++--- .../Java/redkale/conf/source.properties | 5 +-- frameworks/Java/redkale/pom-jdbc.xml | 9 +++--- frameworks/Java/redkale/pom-pgclient.xml | 9 +++--- frameworks/Java/redkale/pom.xml | 8 ++--- .../Java/redkale/redkale-block.dockerfile | 2 +- .../Java/redkale/redkale-graalvm.dockerfile | 4 +-- .../Java/redkale/redkale-jdbc.dockerfile | 2 +- .../Java/redkale/redkale-native.dockerfile | 10 +++--- .../Java/redkale/redkale-pgclient.dockerfile | 2 +- frameworks/Java/redkale/redkale.dockerfile | 2 +- .../redkalex/benchmark/BenchmarkService.java | 9 ++++-- .../org/redkalex/benchmark/FortuneRender.java | 31 ++++++++++--------- 14 files changed, 58 insertions(+), 48 deletions(-) diff --git a/frameworks/Java/redkale/BenchmarkService.java b/frameworks/Java/redkale/BenchmarkService.java index 06e760bf879..39e9956a75d 100644 --- a/frameworks/Java/redkale/BenchmarkService.java +++ b/frameworks/Java/redkale/BenchmarkService.java @@ -12,6 +12,7 @@ import org.redkale.net.http.*; import org.redkale.service.AbstractService; import org.redkale.source.DataSource; +import org.redkale.util.AnyValue; /** * 测试redkale-jdbc, 需要覆盖到原BenchmarkService @@ -26,6 +27,10 @@ public class BenchmarkService extends AbstractService { @Resource private DataSource source; + public void init(AnyValue conf) { + source.finds(CachedWorld.class, 1); + } + @NonBlocking @RestMapping(auth = false) public byte[] plaintext() { diff --git a/frameworks/Java/redkale/conf/application.xml b/frameworks/Java/redkale/conf/application.xml index d7157c9f8d3..aa535805113 100644 --- a/frameworks/Java/redkale/conf/application.xml +++ b/frameworks/Java/redkale/conf/application.xml @@ -4,19 +4,19 @@ - - + - - + + + diff --git a/frameworks/Java/redkale/conf/source.properties b/frameworks/Java/redkale/conf/source.properties index 9efb8cd4158..f88e22a2a12 100644 --- a/frameworks/Java/redkale/conf/source.properties +++ b/frameworks/Java/redkale/conf/source.properties @@ -4,5 +4,6 @@ redkale.datasource[].url = jdbc:postgresql://tfb-database:5432/hello_world redkale.datasource[].user = benchmarkdbuser redkale.datasource[].password = benchmarkdbpass -redkale.datasource[].warnslowms = 0 -redkale.datasource[].errorslowms = 0 +redkale.datasource[].non-blocking = true +redkale.datasource[].warn-slowms = 0 +redkale.datasource[].error-slowms = 0 diff --git a/frameworks/Java/redkale/pom-jdbc.xml b/frameworks/Java/redkale/pom-jdbc.xml index 93df4fb9464..e617e4e4059 100644 --- a/frameworks/Java/redkale/pom-jdbc.xml +++ b/frameworks/Java/redkale/pom-jdbc.xml @@ -7,12 +7,12 @@ org.redkale.boot.Application - 2.9.0-SNAPSHOT + 2.8.0-SNAPSHOT 1.3.0-SNAPSHOT - 42.6.0 + 42.7.2 UTF-8 - 18 - 18 + 21 + 21 @@ -77,7 +77,6 @@ UTF-8 -parameters - --enable-preview true diff --git a/frameworks/Java/redkale/pom-pgclient.xml b/frameworks/Java/redkale/pom-pgclient.xml index 1e7315a9ff2..47f212a3053 100644 --- a/frameworks/Java/redkale/pom-pgclient.xml +++ b/frameworks/Java/redkale/pom-pgclient.xml @@ -7,13 +7,13 @@ org.redkale.boot.Application - 2.9.0-SNAPSHOT - 1.3.0-SNAPSHOT + 2.8.0-SNAPSHOT + 1.2.0-SNAPSHOT 4.5.8 2.1 UTF-8 - 18 - 18 + 21 + 21 @@ -84,7 +84,6 @@ UTF-8 -parameters - --enable-preview true
diff --git a/frameworks/Java/redkale/pom.xml b/frameworks/Java/redkale/pom.xml index 78ffcbdd93b..8844a8b7aff 100644 --- a/frameworks/Java/redkale/pom.xml +++ b/frameworks/Java/redkale/pom.xml @@ -7,11 +7,11 @@ org.redkale.boot.Application - 2.9.0-SNAPSHOT - 1.3.0-SNAPSHOT + 2.8.0-SNAPSHOT + 1.2.0-SNAPSHOT UTF-8 - 11 - 11 + 21 + 21 diff --git a/frameworks/Java/redkale/redkale-block.dockerfile b/frameworks/Java/redkale/redkale-block.dockerfile index 36d75c9db4d..b163c60e53f 100644 --- a/frameworks/Java/redkale/redkale-block.dockerfile +++ b/frameworks/Java/redkale/redkale-block.dockerfile @@ -1,4 +1,4 @@ -FROM maven:3.8.6-openjdk-18-slim as maven +FROM maven:3.9.6-amazoncorretto-21-debian as maven WORKDIR /redkale COPY src src COPY conf conf diff --git a/frameworks/Java/redkale/redkale-graalvm.dockerfile b/frameworks/Java/redkale/redkale-graalvm.dockerfile index 25ad428f6c8..0e3a9a4a597 100644 --- a/frameworks/Java/redkale/redkale-graalvm.dockerfile +++ b/frameworks/Java/redkale/redkale-graalvm.dockerfile @@ -1,4 +1,4 @@ -FROM maven:3.8.6-openjdk-18-slim as maven +FROM maven:3.9.6-amazoncorretto-21-debian as maven WORKDIR /redkale COPY src src COPY conf conf @@ -6,7 +6,7 @@ COPY pom.xml pom.xml RUN mvn package -q -FROM ghcr.io/graalvm/jdk-community:21.0.0 +FROM ghcr.io/graalvm/jdk-community:22.0.2 WORKDIR /redkale COPY conf conf COPY --from=maven /redkale/target/redkale-benchmark-1.0.0.jar redkale-benchmark.jar diff --git a/frameworks/Java/redkale/redkale-jdbc.dockerfile b/frameworks/Java/redkale/redkale-jdbc.dockerfile index 4588baf43f1..b39997adf5f 100644 --- a/frameworks/Java/redkale/redkale-jdbc.dockerfile +++ b/frameworks/Java/redkale/redkale-jdbc.dockerfile @@ -1,4 +1,4 @@ -FROM maven:3.8.6-openjdk-18-slim as maven +FROM maven:3.9.6-amazoncorretto-21-debian as maven WORKDIR /redkale COPY src src COPY conf conf diff --git a/frameworks/Java/redkale/redkale-native.dockerfile b/frameworks/Java/redkale/redkale-native.dockerfile index ae8e0cd7895..56fa1921f96 100644 --- a/frameworks/Java/redkale/redkale-native.dockerfile +++ b/frameworks/Java/redkale/redkale-native.dockerfile @@ -1,4 +1,4 @@ -FROM maven:3.8.6-openjdk-18-slim as maven +FROM maven:3.9.6-amazoncorretto-21-debian as maven WORKDIR /redkale COPY src src COPY conf conf @@ -6,15 +6,15 @@ COPY pom.xml pom.xml RUN mvn package -q -FROM ghcr.io/graalvm/graalvm-ce:ol9-java17-22.3.3 -RUN gu install native-image +FROM ghcr.io/graalvm/native-image-community:22.0.2 as native WORKDIR /redkale COPY conf conf COPY --from=maven /redkale/target/redkale-benchmark-1.0.0.jar redkale-benchmark.jar - RUN native-image -H:+ReportExceptionStackTraces --report-unsupported-elements-at-runtime -jar redkale-benchmark.jar -RUN ls -lh +FROM ghcr.io/graalvm/jdk-community:22.0.2 +WORKDIR /redkale +COPY --from=native /redkale/redkale-benchmark redkale-benchmark EXPOSE 8080 diff --git a/frameworks/Java/redkale/redkale-pgclient.dockerfile b/frameworks/Java/redkale/redkale-pgclient.dockerfile index fdc4786a478..6da37e715c5 100644 --- a/frameworks/Java/redkale/redkale-pgclient.dockerfile +++ b/frameworks/Java/redkale/redkale-pgclient.dockerfile @@ -1,4 +1,4 @@ -FROM maven:3.8.6-openjdk-18-slim as maven +FROM maven:3.9.6-amazoncorretto-21-debian as maven WORKDIR /redkale COPY src src COPY conf conf diff --git a/frameworks/Java/redkale/redkale.dockerfile b/frameworks/Java/redkale/redkale.dockerfile index 8982ae3b16d..4bb09a8dd56 100644 --- a/frameworks/Java/redkale/redkale.dockerfile +++ b/frameworks/Java/redkale/redkale.dockerfile @@ -1,4 +1,4 @@ -FROM maven:3.8.6-openjdk-18-slim as maven +FROM maven:3.9.6-amazoncorretto-21-debian as maven WORKDIR /redkale COPY src src COPY conf conf diff --git a/frameworks/Java/redkale/src/main/java/org/redkalex/benchmark/BenchmarkService.java b/frameworks/Java/redkale/src/main/java/org/redkalex/benchmark/BenchmarkService.java index 20f816362d2..48af592f928 100644 --- a/frameworks/Java/redkale/src/main/java/org/redkalex/benchmark/BenchmarkService.java +++ b/frameworks/Java/redkale/src/main/java/org/redkalex/benchmark/BenchmarkService.java @@ -13,6 +13,7 @@ import org.redkale.net.http.*; import org.redkale.service.AbstractService; import org.redkale.source.DataSource; +import org.redkale.util.AnyValue; /** * @@ -27,6 +28,10 @@ public class BenchmarkService extends AbstractService { @Resource private DataSource source; + public void init(AnyValue conf) { + source.finds(CachedWorld.class, 1); + } + @RestMapping(auth = false) public byte[] plaintext() { return helloBytes; @@ -53,8 +58,8 @@ public CompletableFuture> updates(int q) { IntStream ids = ThreadLocalRandom.current().ints(size, 1, 10001); int[] newNumbers = ThreadLocalRandom.current().ints(size, 1, 10001).toArray(); return source.findsListAsync(World.class, ids.boxed()) - .thenCompose(words -> source.updateAsync(World.updateNewNumbers(words, newNumbers)) - .thenApply(v -> words)); + .thenCompose(words -> source.updateAsync(World.updateNewNumbers(words, newNumbers)) + .thenApply(v -> words)); } @RestMapping(auth = false) diff --git a/frameworks/Java/redkale/src/main/java/org/redkalex/benchmark/FortuneRender.java b/frameworks/Java/redkale/src/main/java/org/redkalex/benchmark/FortuneRender.java index 201c58bc741..651864d0da5 100644 --- a/frameworks/Java/redkale/src/main/java/org/redkalex/benchmark/FortuneRender.java +++ b/frameworks/Java/redkale/src/main/java/org/redkalex/benchmark/FortuneRender.java @@ -7,6 +7,7 @@ import java.nio.charset.StandardCharsets; import java.util.List; +import java.util.function.Function; import org.redkale.convert.Convert; import org.redkale.net.http.*; import org.redkale.util.*; @@ -19,7 +20,9 @@ public class FortuneRender implements org.redkale.net.http.HttpRender { private static final String contentType = "text/html; charset=utf-8"; - private static final byte[] text1 = "Fortunes".getBytes(StandardCharsets.UTF_8); + private static final byte[] text1 = + "Fortunes
idmessage
" + .getBytes(StandardCharsets.UTF_8); private static final byte[] text2 = "
idmessage
".getBytes(StandardCharsets.UTF_8); @@ -29,9 +32,9 @@ public class FortuneRender implements org.redkale.net.http.HttpRender { private static final byte[] text5 = "
".getBytes(StandardCharsets.UTF_8); - private final ThreadLocal localByteArray = ThreadLocal.withInitial(() -> new ByteArray(1280)); + private static final String arrayName = "fortuneByteArray"; - private final ThreadLocal localTmpArray = ThreadLocal.withInitial(() -> new ByteArray(128)); + private static final Function arrayFunc = s -> new ByteArray(1280); private byte[][] idBytesCache; @@ -53,12 +56,11 @@ public void init(HttpContext context, AnyValue config) { @Override public void renderTo(HttpRequest request, HttpResponse response, Convert convert, HttpScope scope) { - ByteArray array = localByteArray.get().clear(); + ByteArray array = request.getSubobjectIfAbsent(arrayName, arrayFunc).clear(); array.put(text1); - ByteArray tmp = localTmpArray.get(); for (Fortune item : (List) scope.getReferObj()) { - array.put(text2).put(escapeId(item.getId())) - .put(text3).put(escapeMessage(tmp, item.getMessage())).put(text4); + ByteArray msg = request.getSubobjectIfAbsent(item.getMessage(), this::escapeMessage); + array.put(text2).put(escapeId(item.getId())).put(text3).put(msg).put(text4); } array.put(text5); response.finish(contentType, array); @@ -72,23 +74,22 @@ private byte[] escapeId(int id) { } } - private ByteArray escapeMessage(ByteArray tmp, String message) { - tmp.clear(); + private ByteArray escapeMessage(String message) { + ByteArray array = new ByteArray(128); CharSequence cs = message; for (int i = 0; i < cs.length(); i++) { char c = cs.charAt(i); byte[] bs = c < escapeCache.length ? escapeCache[c] : null; if (bs != null) { - tmp.put(bs); + array.put(bs); } else if (c < 0x80) { - tmp.put((byte) c); + array.put((byte) c); } else if (c < 0x800) { - tmp.put((byte) (0xc0 | (c >> 6)), (byte) (0x80 | (c & 0x3f))); + array.put((byte) (0xc0 | (c >> 6)), (byte) (0x80 | (c & 0x3f))); } else { - tmp.put((byte) (0xe0 | ((c >> 12))), (byte) (0x80 | ((c >> 6) & 0x3f)), (byte) (0x80 | (c & 0x3f))); + array.put((byte) (0xe0 | (c >> 12)), (byte) (0x80 | ((c >> 6) & 0x3f)), (byte) (0x80 | (c & 0x3f))); } } - return tmp; + return array; } - } From aac290b65e3178e330b8ef2948b953023d0ba4f7 Mon Sep 17 00:00:00 2001 From: SaltyAom Date: Thu, 12 Sep 2024 23:06:55 +0700 Subject: [PATCH 114/204] [Elysia] add compiled configuration, use cluster mode, optimize performance (#9251) * feat(elysia): use cluster mode, static resource, add compiled mode * feat(elysia): use imperative for-loop instead of map to optimize performance --- .../TypeScript/elysia/benchmark_config.json | 23 +++++++ frameworks/TypeScript/elysia/bun.lockb | Bin 4963 -> 3513 bytes .../elysia/elysia-compiled.dockerfile | 15 +++++ .../elysia/elysia-postgres.dockerfile | 6 +- .../elysia/elysia-smol-postgres.dockerfile | 8 +-- .../TypeScript/elysia/elysia.dockerfile | 2 +- frameworks/TypeScript/elysia/package.json | 8 +-- frameworks/TypeScript/elysia/spawn.ts | 18 ------ .../TypeScript/elysia/src/db-handlers.ts | 59 +++++++++--------- frameworks/TypeScript/elysia/src/index.ts | 39 +++++------- frameworks/TypeScript/elysia/src/postgres.ts | 37 ++++++----- frameworks/TypeScript/elysia/src/server.ts | 20 ++++++ 12 files changed, 133 insertions(+), 102 deletions(-) create mode 100644 frameworks/TypeScript/elysia/elysia-compiled.dockerfile delete mode 100644 frameworks/TypeScript/elysia/spawn.ts create mode 100644 frameworks/TypeScript/elysia/src/server.ts diff --git a/frameworks/TypeScript/elysia/benchmark_config.json b/frameworks/TypeScript/elysia/benchmark_config.json index 1a0652745db..04e9073cbe8 100755 --- a/frameworks/TypeScript/elysia/benchmark_config.json +++ b/frameworks/TypeScript/elysia/benchmark_config.json @@ -62,6 +62,29 @@ "display_name": "Elysia [smol] [PostgreSQL]", "notes": "", "versus": "nodejs" + }, + "compiled": { + "json_url": "/json", + "plaintext_url": "/plaintext", + "db_url": "/db", + "query_url": "/queries?queries=", + "update_url": "/updates?queries=", + "fortune_url": "/fortunes", + "port": 8080, + "approach": "Realistic", + "classification": "Micro", + "database": "Postgres", + "framework": "elysia", + "language": "TypeScript", + "flavor": "None", + "orm": "Raw", + "platform": "bun", + "webserver": "None", + "os": "Linux", + "database_os": "Linux", + "display_name": "Elysia [Compiled]", + "notes": "", + "versus": "nodejs" } } ] diff --git a/frameworks/TypeScript/elysia/bun.lockb b/frameworks/TypeScript/elysia/bun.lockb index 7e29924798c25d30517bcca2ed92c9934b0540fa..0020cf63f06be5b698becc47ddfdaa4336096013 100755 GIT binary patch delta 600 zcmaE?wo`h7p60FYj0cti2jnY#70S<@wUYhy!=#8|`@K(c=FNg#Q4GAFb7*;%tM9Z9tQ%OpSJWAA>c-7io3E-Pr* zAmkua_~S>ViP!UlR`spP4Egq@o7s-P-Y~25@z$=`=bp}N1>vTfS=n|oPIl(%nY@P6 zWwQfU1S8i5sN0WlOitsmlLNW*-+u@IvDtz615^nQ=j44nMq(^LA&}?UfY^c)NB}_u zNJ?q44X*-M2TX`-av87IH6v0%ME^7XX0LGh3YryXFG&mD=j`fqjG-MrOb)?QN3zgZ7n(TZH~PPoV9xrqX(n# zWKTwWUT>gLCP1x>K$>xKAd~iF2SyIYZIe$j+B5!~%*kZW7(Ce%NVZSz1d>-LpJXxz zsSp$dT4fE>2h=M*nUPT)ERz6~0h!1F6lDcs9=OaDpo|qzMg$}Z#C&j>TR<5{pbSX8 z6cDolWwh&AfGiLO0T2z61qA^J5JLkE1qBNO$ZsI~Kr}FT;edeoW?+T*EW&ER@$A#y+c3j#&-(1Fj{V|p-L0h|~^u}4Q zH!s(nv5aX~)1>wHX4jR>WZc}!vYWAMZzKcK5YK?wsa7tVyTPpwIduTePB+$K|; z;8>)+%D@%n!bcjYgx?Y<#hI^804q5N78->Zw>^>Li~@#=O|_d$k7uR4u8PdJ
Qfl|1()92?QpJt!in3HqP~aSWo(a4 zC_BI_Cc1XAVD8s_*Ww}$mO5*7IICPSoQPyFFpge$m~LKz1`}P48=f$ql^;|7u)sE$TVTLi=W0?UKpi43&~(m zbix3OT0oEW^Mxf&T&n^LCohr@YY+*`Fn)W~`i%X!P9W|RKDSm&r-&-{8Rn?No0_^>h&#<{n4qyw|EWjSYI9Y-H2-gBoQUQW3Jd=w! z?48+JrAo}eSe$ImsVD_f z4$}rQaRF4>C%(x^oLbUA5pd>)KPg^VCvBVxeN%vr3}zESYZOxW2$Flrf0(7zzq0_BuOz+70jx_uFFz#}$}BIQ9K|gy3g-bemKW=Sy=F8yo=080;)vj>Vmy(3Q|8=kbMRKOc#%C diff --git a/frameworks/TypeScript/elysia/elysia-compiled.dockerfile b/frameworks/TypeScript/elysia/elysia-compiled.dockerfile new file mode 100644 index 00000000000..73de65fcfa7 --- /dev/null +++ b/frameworks/TypeScript/elysia/elysia-compiled.dockerfile @@ -0,0 +1,15 @@ +FROM oven/bun:1.1 + +EXPOSE 8080 + +COPY . . + +ENV NODE_ENV production + +RUN bun install --production + +ENV DATABASE postgres + +RUN bun run compile + +CMD ["./server"] diff --git a/frameworks/TypeScript/elysia/elysia-postgres.dockerfile b/frameworks/TypeScript/elysia/elysia-postgres.dockerfile index 40ff868c528..68ce83d3325 100644 --- a/frameworks/TypeScript/elysia/elysia-postgres.dockerfile +++ b/frameworks/TypeScript/elysia/elysia-postgres.dockerfile @@ -8,8 +8,8 @@ ENV NODE_ENV production RUN bun install --production -RUN bun run build - ENV DATABASE postgres -CMD ["bun", "spawn.ts"] +RUN bun run build + +CMD ["bun", "./dist/index.js"] diff --git a/frameworks/TypeScript/elysia/elysia-smol-postgres.dockerfile b/frameworks/TypeScript/elysia/elysia-smol-postgres.dockerfile index de7b9d63bb0..fa6c7a7aca7 100644 --- a/frameworks/TypeScript/elysia/elysia-smol-postgres.dockerfile +++ b/frameworks/TypeScript/elysia/elysia-smol-postgres.dockerfile @@ -6,12 +6,12 @@ COPY . . ENV NODE_ENV production -RUN bun install --production - -RUN bun run build +RUN bun install ENV DATABASE postgres +RUN bun run build + RUN sed -i 's/smol = false/smol = true/g' bunfig.toml -CMD ["bun", "spawn.ts"] +CMD ["bun", "./dist/index.js"] diff --git a/frameworks/TypeScript/elysia/elysia.dockerfile b/frameworks/TypeScript/elysia/elysia.dockerfile index 3ed07652df1..f95b8706c6c 100644 --- a/frameworks/TypeScript/elysia/elysia.dockerfile +++ b/frameworks/TypeScript/elysia/elysia.dockerfile @@ -10,4 +10,4 @@ RUN bun install --production RUN bun run build -CMD ["bun", "spawn.ts"] +CMD ["bun", "./dist/index.js"] diff --git a/frameworks/TypeScript/elysia/package.json b/frameworks/TypeScript/elysia/package.json index ba38bf05ee6..c23716506c8 100644 --- a/frameworks/TypeScript/elysia/package.json +++ b/frameworks/TypeScript/elysia/package.json @@ -3,16 +3,16 @@ "version": "0.0.1", "module": "src/index.js", "devDependencies": { - "bun-types": "^1.1.23", "typescript": "^5.5.4" }, "scripts": { "dev": "bun run --watch src/index.ts", "start": "bun run src/index.ts", - "build": "bun build --compile --minify --outfile server src/index.ts" + "build": "bun build --minify --target bun --outdir dist src/index.ts", + "compile": "bun build --compile --minify --target bun --outfile server src/index.ts" }, "dependencies": { - "elysia": "^1.1.6", + "elysia": "^1.1.12", "postgres": "^3.4.4" } -} \ No newline at end of file +} diff --git a/frameworks/TypeScript/elysia/spawn.ts b/frameworks/TypeScript/elysia/spawn.ts deleted file mode 100644 index 3bf8959c230..00000000000 --- a/frameworks/TypeScript/elysia/spawn.ts +++ /dev/null @@ -1,18 +0,0 @@ -const cpus = navigator.hardwareConcurrency; -const buns = new Array(cpus); - -for (let i = 0; i < cpus; i++) { - buns[i] = Bun.spawn(['./server'], { - stdio: ['inherit', 'inherit', 'inherit'], - env: { ...process.env }, - }); -} - -function kill() { - for (const bun of buns) { - bun.kill(); - } -} - -process.on('SIGINT', kill); -process.on('exit', kill); \ No newline at end of file diff --git a/frameworks/TypeScript/elysia/src/db-handlers.ts b/frameworks/TypeScript/elysia/src/db-handlers.ts index d75e91ff1a5..b75ccfdea60 100644 --- a/frameworks/TypeScript/elysia/src/db-handlers.ts +++ b/frameworks/TypeScript/elysia/src/db-handlers.ts @@ -1,64 +1,63 @@ -import Elysia from 'elysia'; -import * as db from './postgres'; -import { Fortune } from './types'; +import { Elysia, t } from "elysia"; +import * as db from "./postgres"; +import { Fortune } from "./types"; -function rand () { - return Math.ceil(Math.random() * 10000) +function rand() { + return Math.ceil(Math.random() * 10000); } -function parseQueriesNumber (q?: string) { - return Math.min(parseInt(q || '1') || 1, 500) +function parseQueriesNumber(q?: string) { + return Math.min(parseInt(q || "1") || 1, 500); } -function renderTemplate (fortunes: Fortune[]) { +function renderTemplate(fortunes: Fortune[]) { const n = fortunes.length; - let html = ''; + let html = ""; for (let i = 0; i < n; i++) { html += `${fortunes[i].id}${Bun.escapeHTML( - fortunes[i].message + fortunes[i].message, )}`; } return `Fortunes${html}
idmessage
`; } -const dbHandlers = new Elysia({ - name: 'db-handlers', -}) - .onAfterHandle(({ set }) => { - set.headers['server'] = 'Elysia'; +export const dbHandlers = new Elysia() + .headers({ + server: "Elysia", }) - - .get('/db', () => db.find(rand())) - - .get('/fortunes', async ({ set }) => { + .get("/db", () => db.find(rand())) + .get("/fortunes", async (c) => { const fortunes = await db.fortunes(); fortunes.push({ id: 0, - message: 'Additional fortune added at request time.', + message: "Additional fortune added at request time.", + }); + + fortunes.sort((a, b) => { + if (a.message < b.message) return -1; + + return 1; }); - fortunes.sort((a, b) => (a.message < b.message ? -1 : 1)); + c.set.headers["content-type"] = "text/html; charset=utf-8"; - set.headers['content-type'] = 'text/html; charset=utf-8'; return renderTemplate(fortunes); }) - - .get('/queries', async ({ query }) => { - const num = parseQueriesNumber(query.queries) + .get("/queries", (c) => { + const num = parseQueriesNumber(c.query.queries); const worldPromises = new Array(num); for (let i = 0; i < num; i++) { worldPromises[i] = db.find(rand()); } - return await Promise.all(worldPromises); + return Promise.all(worldPromises); }) - - .get('/updates', async ({ query }) => { - const num = parseQueriesNumber(query.queries) + .get("/updates", async (c) => { + const num = parseQueriesNumber(c.query.queries); const worldPromises = new Array(num); for (let i = 0; i < num; i++) { @@ -74,5 +73,3 @@ const dbHandlers = new Elysia({ await db.bulkUpdate(worlds); return worlds; }); - -export default dbHandlers; diff --git a/frameworks/TypeScript/elysia/src/index.ts b/frameworks/TypeScript/elysia/src/index.ts index af24275c128..b34edbde4b7 100644 --- a/frameworks/TypeScript/elysia/src/index.ts +++ b/frameworks/TypeScript/elysia/src/index.ts @@ -1,29 +1,20 @@ -import { Elysia } from 'elysia'; -import dbHandlers from './db-handlers'; +import cluster from "node:cluster"; +import os from "node:os"; +import process from "node:process"; -const app = new Elysia({ - serve: { - reusePort: true, - }, -}) - .get('/plaintext', ({ set }) => { - set.headers['server'] = 'Elysia'; - return 'Hello, World!'; - }) +if (cluster.isPrimary) { + console.log(`Primary ${process.pid} is running`); - .get('/json', ({ set }) => { - set.headers = { - 'content-type': 'application/json', - 'server': 'Elysia', - }; + const numCPUs = os.availableParallelism(); + for (let i = 0; i < numCPUs; i++) { + cluster.fork(); + } - return JSON.stringify({ message: 'Hello, World!' }); + cluster.on("exit", (worker) => { + console.log(`worker ${worker.process.pid} died`); + process.exit(1); }); - -if (Bun.env.DATABASE) { - app.use(dbHandlers); +} else { + await import("./server"); + console.log(`Worker ${process.pid} started`); } - -app.listen(8080); - -console.info(`🦊 Elysia is running at ${app.server!.url}`); diff --git a/frameworks/TypeScript/elysia/src/postgres.ts b/frameworks/TypeScript/elysia/src/postgres.ts index 5c9ba1dbcbe..cc6d4389a02 100644 --- a/frameworks/TypeScript/elysia/src/postgres.ts +++ b/frameworks/TypeScript/elysia/src/postgres.ts @@ -1,27 +1,30 @@ -import postgres from 'postgres'; -import { Fortune, World } from './types'; +import postgres from "postgres"; +import { Fortune, World } from "./types"; const sql = postgres({ - host: 'tfb-database', - user: 'benchmarkdbuser', - password: 'benchmarkdbpass', - database: 'hello_world', + host: "tfb-database", + user: "benchmarkdbuser", + password: "benchmarkdbpass", + database: "hello_world", max: 1, }); -export const fortunes = () => - sql`SELECT id, message FROM fortune`; +export const fortunes = () => sql`SELECT id, message FROM fortune`; export const find = (id: number) => sql`SELECT id, randomNumber FROM world WHERE id = ${id}`.then( - (arr) => arr[0] + (arr) => arr[0], ); -export const bulkUpdate = (worlds: World[]) => - sql`UPDATE world SET randomNumber = (update_data.randomNumber)::int - FROM (VALUES ${sql( - worlds - .map((world) => [world.id, world.randomNumber]) - .sort((a, b) => (a[0] < b[0] ? -1 : 1)) - )}) AS update_data (id, randomNumber) - WHERE world.id = (update_data.id)::int`; +export const bulkUpdate = (worlds: World[]) => { + worlds = worlds.toSorted((a, b) => a.id - b.id); + + const values = new Array(worlds.length); + for (let i = 0; i < worlds.length; i++) { + values[i] = [worlds[i].id, worlds[i].randomNumber]; + } + + return sql`UPDATE world SET randomNumber = (update_data.randomNumber)::int + FROM (VALUES ${sql(values)}) AS update_data (id, randomNumber) + WHERE world.id = (update_data.id)::int`; +}; diff --git a/frameworks/TypeScript/elysia/src/server.ts b/frameworks/TypeScript/elysia/src/server.ts new file mode 100644 index 00000000000..7c2c46d224d --- /dev/null +++ b/frameworks/TypeScript/elysia/src/server.ts @@ -0,0 +1,20 @@ +import { Elysia } from "elysia"; +import { dbHandlers } from "./db-handlers"; + +const app = new Elysia() + .headers({ + server: "Elysia", + }) + .get("/plaintext", "Hello, World!") + // As state on xiv in https://github.com/TechEmpower/FrameworkBenchmarks/wiki/Project-Information-Framework-Tests-Overview#requirements + // The serialization to JSON must not be cached; + // the computational effort to serialize an object to JSON must occur within the scope of handling each request. + .get("/json", () => ({ message: "Hello, World!" })) + .use((app) => { + if (Bun.env.DATABASE) app.use(dbHandlers); + + return app; + }) + .listen(8080); + +console.info(`🦊 Elysia is running at ${app.server!.url}`); From 4a7b80c4cdadd6be50f0a1995a19bf6fbc94e4e2 Mon Sep 17 00:00:00 2001 From: Vladimir Shchur Date: Thu, 12 Sep 2024 19:07:09 +0300 Subject: [PATCH 115/204] [F#/Oxpecker] Simplified connection string (should benefit performance as well) (#9255) --- frameworks/FSharp/oxpecker/src/App/Common.fs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frameworks/FSharp/oxpecker/src/App/Common.fs b/frameworks/FSharp/oxpecker/src/App/Common.fs index 0b62abdefee..47a63e2108e 100644 --- a/frameworks/FSharp/oxpecker/src/App/Common.fs +++ b/frameworks/FSharp/oxpecker/src/App/Common.fs @@ -26,7 +26,7 @@ module Common = } [] - let ConnectionString = "Server=tfb-database;Database=hello_world;User Id=benchmarkdbuser;Password=benchmarkdbpass;SSL Mode=Disable;Maximum Pool Size=1024;NoResetOnClose=true;Enlist=false;Max Auto Prepare=4;Multiplexing=true;Write Coalescing Buffer Threshold Bytes=1000" + let ConnectionString = "Server=tfb-database;Database=hello_world;User Id=benchmarkdbuser;Password=benchmarkdbpass;Maximum Pool Size=1024;NoResetOnClose=true;Enlist=false;Max Auto Prepare=3" let FortuneComparer = { new IComparer with From 8222e5dea25315164b6aced97125527f0704c724 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=A5=BF=E4=B8=9C?= Date: Fri, 13 Sep 2024 00:07:32 +0800 Subject: [PATCH 116/204] [Java] Update Solon Version To 2.9.2 (#9260) * Update Solon Version To 2.9.1 * Update Solon Version To 2.9.1 * Update Solon Jdk To 21 * Update Solon Jdk To 21 * Update Solon Jdk To 21 * Update Solon Jdk To 21 * Update Solon Jdk To 21 * Update Solon Version To 2.9.2 * Add Solon-Virtual * Remove solon-virtual --- frameworks/Java/solon/pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frameworks/Java/solon/pom.xml b/frameworks/Java/solon/pom.xml index a9568927908..035ad60951a 100644 --- a/frameworks/Java/solon/pom.xml +++ b/frameworks/Java/solon/pom.xml @@ -5,7 +5,7 @@ org.noear solon-parent - 2.9.1 + 2.9.2 hello @@ -26,7 +26,7 @@ org.noear - solon.serialization.snack3 + solon.serialization.fastjson2 ${solon.version} From 64398bce241937e42ab2a212f621f0c3fb0ef9d5 Mon Sep 17 00:00:00 2001 From: MARiA so cute <33935209+NathanFreeman@users.noreply.github.com> Date: Fri, 13 Sep 2024 00:09:35 +0800 Subject: [PATCH 117/204] optimize swoole (#9261) --- frameworks/PHP/swoole/database.php | 2 +- frameworks/PHP/swoole/php.ini | 1 + frameworks/PHP/swoole/swoole-async-mysql.dockerfile | 1 + frameworks/PHP/swoole/swoole-async-postgres.dockerfile | 1 + frameworks/PHP/swoole/swoole-server.php | 6 ++---- frameworks/PHP/swoole/swoole-sync-mysql.dockerfile | 1 + frameworks/PHP/swoole/swoole-sync-postgres.dockerfile | 3 ++- 7 files changed, 9 insertions(+), 6 deletions(-) diff --git a/frameworks/PHP/swoole/database.php b/frameworks/PHP/swoole/database.php index 19aac390968..97d3af6887a 100644 --- a/frameworks/PHP/swoole/database.php +++ b/frameworks/PHP/swoole/database.php @@ -144,7 +144,7 @@ public static function init(string $driver): void ->withUsername('benchmarkdbuser') ->withPassword('benchmarkdbpass'); - self::$pool = new PDOPool($config, 128); + self::$pool = new PDOPool($config, intval(1400 / swoole_cpu_num())); self::$driver = $driver; } diff --git a/frameworks/PHP/swoole/php.ini b/frameworks/PHP/swoole/php.ini index 082e86dedbc..089c4837bd5 100644 --- a/frameworks/PHP/swoole/php.ini +++ b/frameworks/PHP/swoole/php.ini @@ -1,3 +1,4 @@ +zend_extension=opcache.so opcache.enable=1 opcache.enable_cli=1 opcache.validate_timestamps=0 diff --git a/frameworks/PHP/swoole/swoole-async-mysql.dockerfile b/frameworks/PHP/swoole/swoole-async-mysql.dockerfile index 82dbe32833f..ebfe9084357 100644 --- a/frameworks/PHP/swoole/swoole-async-mysql.dockerfile +++ b/frameworks/PHP/swoole/swoole-async-mysql.dockerfile @@ -2,6 +2,7 @@ FROM ubuntu:24.04 ENV SWOOLE_VERSION 5.1.4 ENV ENABLE_COROUTINE 1 +ENV CPU_MULTIPLES 1 ENV DATABASE_DRIVER mysql ARG DEBIAN_FRONTEND=noninteractive diff --git a/frameworks/PHP/swoole/swoole-async-postgres.dockerfile b/frameworks/PHP/swoole/swoole-async-postgres.dockerfile index 4a6b27b2bb0..f8cd24cc887 100644 --- a/frameworks/PHP/swoole/swoole-async-postgres.dockerfile +++ b/frameworks/PHP/swoole/swoole-async-postgres.dockerfile @@ -2,6 +2,7 @@ FROM ubuntu:24.04 ENV SWOOLE_VERSION 5.1.4 ENV ENABLE_COROUTINE 1 +ENV CPU_MULTIPLES 1 ENV DATABASE_DRIVER pgsql ARG DEBIAN_FRONTEND=noninteractive diff --git a/frameworks/PHP/swoole/swoole-server.php b/frameworks/PHP/swoole/swoole-server.php index 3794c364cb7..13050d75ebb 100644 --- a/frameworks/PHP/swoole/swoole-server.php +++ b/frameworks/PHP/swoole/swoole-server.php @@ -8,9 +8,8 @@ $enableCoroutine = getenv('ENABLE_COROUTINE') == 1; $connection = $enableCoroutine ? Connections::class : Connection::class; -$server = new Server('0.0.0.0', 8080); $setting = [ - 'worker_num' => swoole_cpu_num() * 4, + 'worker_num' => swoole_cpu_num() * ((int) getenv('CPU_MULTIPLES')), 'log_file' => '/dev/null', 'enable_coroutine' => $enableCoroutine, 'enable_reuse_port' => true @@ -18,12 +17,11 @@ if ($enableCoroutine) { $setting['hook_flags'] = SWOOLE_HOOK_ALL; - $setting['worker_num'] = swoole_cpu_num(); } +$server = new Server('0.0.0.0', 8080); $server->set($setting); - $server->on('workerStart', function () use ($connection) { $connection::init(getenv('DATABASE_DRIVER')); }); diff --git a/frameworks/PHP/swoole/swoole-sync-mysql.dockerfile b/frameworks/PHP/swoole/swoole-sync-mysql.dockerfile index 97a0e11d111..6c1278bed67 100644 --- a/frameworks/PHP/swoole/swoole-sync-mysql.dockerfile +++ b/frameworks/PHP/swoole/swoole-sync-mysql.dockerfile @@ -2,6 +2,7 @@ FROM ubuntu:24.04 ENV SWOOLE_VERSION 5.1.4 ENV ENABLE_COROUTINE 0 +ENV CPU_MULTIPLES 1 ENV DATABASE_DRIVER mysql ARG DEBIAN_FRONTEND=noninteractive diff --git a/frameworks/PHP/swoole/swoole-sync-postgres.dockerfile b/frameworks/PHP/swoole/swoole-sync-postgres.dockerfile index 1b5a68b6169..8651d205921 100644 --- a/frameworks/PHP/swoole/swoole-sync-postgres.dockerfile +++ b/frameworks/PHP/swoole/swoole-sync-postgres.dockerfile @@ -2,6 +2,7 @@ FROM ubuntu:24.04 ENV SWOOLE_VERSION 5.1.4 ENV ENABLE_COROUTINE 0 +ENV CPU_MULTIPLES 4 ENV DATABASE_DRIVER pgsql ARG DEBIAN_FRONTEND=noninteractive @@ -15,7 +16,7 @@ RUN apt update -yqq > /dev/null \ && cd /tmp/swoole-src-${SWOOLE_VERSION} \ && phpize > /dev/null \ && ./configure > /dev/null \ - && make -j2 > /dev/null \ + && make -j8 > /dev/null \ && make install > /dev/null \ && echo "extension=swoole.so" > /etc/php/8.3/cli/conf.d/50-swoole.ini From 1d0f0af6294c9adc0f055bdef66a2c0c2f4b1a13 Mon Sep 17 00:00:00 2001 From: Denis Stepanov Date: Thu, 12 Sep 2024 18:10:36 +0200 Subject: [PATCH 118/204] Micronaut: Use JTE template engine and GraalVM 22 (#9262) * Micronaut: Use JTE template engine and GraalVM 22 * CR * User Graalvm 21 for Micronaut Data --- .../io.micronaut.benchmark.module.gradle | 2 +- frameworks/Java/micronaut/common/build.gradle | 24 +++++---- .../AbstractBenchmarkController.java | 15 ++++++ .../controller/AsyncBenchmarkController.java | 13 +---- .../controller/BenchmarkController.java | 17 ++---- .../controller/FortunesBodyWriter.java | 54 +++++++++++++++++++ .../ReactiveBenchmarkController.java | 15 +----- .../repository/FortuneRepository.java | 3 +- .../common/src/main/jte/fortunes.jte | 4 ++ .../main/resources/views/fortunes.rocker.html | 8 --- frameworks/Java/micronaut/gradle.properties | 2 +- .../java/benchmark/JdbcWorldRepository.java | 2 + .../micronaut/micronaut-graalvm.dockerfile | 2 +- .../micronaut-jdbc-graalvm.dockerfile | 2 +- .../java/benchmark/JdbcFortuneRepository.java | 2 +- .../micronaut-r2dbc-graalvm.dockerfile | 2 +- 16 files changed, 104 insertions(+), 63 deletions(-) create mode 100644 frameworks/Java/micronaut/common/src/main/java/benchmark/controller/FortunesBodyWriter.java create mode 100644 frameworks/Java/micronaut/common/src/main/jte/fortunes.jte delete mode 100644 frameworks/Java/micronaut/common/src/main/resources/views/fortunes.rocker.html diff --git a/frameworks/Java/micronaut/buildSrc/src/main/groovy/io.micronaut.benchmark.module.gradle b/frameworks/Java/micronaut/buildSrc/src/main/groovy/io.micronaut.benchmark.module.gradle index 43a854cf848..dcb6b3389fc 100644 --- a/frameworks/Java/micronaut/buildSrc/src/main/groovy/io.micronaut.benchmark.module.gradle +++ b/frameworks/Java/micronaut/buildSrc/src/main/groovy/io.micronaut.benchmark.module.gradle @@ -28,7 +28,7 @@ dependencies { } graalvmNative.binaries.all { - buildArgs.add("--initialize-at-build-time=views") + buildArgs.add("--initialize-at-build-time=gg.jte.generated.precompiled") } test { diff --git a/frameworks/Java/micronaut/common/build.gradle b/frameworks/Java/micronaut/common/build.gradle index c254fb8e743..8153fd5d8ea 100644 --- a/frameworks/Java/micronaut/common/build.gradle +++ b/frameworks/Java/micronaut/common/build.gradle @@ -1,7 +1,7 @@ plugins { id 'java' id "io.micronaut.library" - id "nu.studer.rocker" version "3.0.4" + id "gg.jte.gradle" version "3.1.12" } group 'io.micronaut.benchmark' @@ -16,14 +16,10 @@ micronaut { testRuntime "junit5" } -rocker { - configurations { - main { - templateDir = file('src/main/resources') - outputDir = file('build/generated/rocker') - optimize = true - } - } +jte { + sourceDirectory = file("src/main/jte").toPath() + generate() + binaryStaticContent = true } dependencies { @@ -38,7 +34,8 @@ dependencies { transitive = false } - implementation("com.fizzed:rocker-runtime") + // Switch to BOM version after https://github.com/micronaut-projects/micronaut-views/issues/876 + implementation("gg.jte:jte-runtime:3.1.12") runtimeOnly("ch.qos.logback:logback-classic") runtimeOnly("org.yaml:snakeyaml") @@ -46,4 +43,11 @@ dependencies { test { useJUnitPlatform() +} + +// Gradle requires that generateJte is run before some tasks +tasks.configureEach { + if (name == "inspectRuntimeClasspath") { + mustRunAfter("generateJte") + } } \ No newline at end of file diff --git a/frameworks/Java/micronaut/common/src/main/java/benchmark/controller/AbstractBenchmarkController.java b/frameworks/Java/micronaut/common/src/main/java/benchmark/controller/AbstractBenchmarkController.java index 637649b448e..8f595d99931 100644 --- a/frameworks/Java/micronaut/common/src/main/java/benchmark/controller/AbstractBenchmarkController.java +++ b/frameworks/Java/micronaut/common/src/main/java/benchmark/controller/AbstractBenchmarkController.java @@ -5,6 +5,7 @@ import java.util.ArrayList; import java.util.Collections; +import java.util.Comparator; import java.util.List; import java.util.concurrent.ThreadLocalRandom; import java.util.stream.IntStream; @@ -12,6 +13,20 @@ public class AbstractBenchmarkController { protected final Integer[] boxed = IntStream.range(1, 10001).boxed().toArray(Integer[]::new); + private static final Comparator FORTUNES_COMPARATOR = new Comparator<>() { + @Override + public int compare(Fortune o1, Fortune o2) { + return o1.message().compareTo(o2.message()); + } + }; + + protected List prepareFortunes(List fortuneList) { + List all = new ArrayList<>(fortuneList.size() + 1); + all.add(new Fortune(0, "Additional fortune added at request time.")); + all.addAll(fortuneList); + all.sort(FORTUNES_COMPARATOR); + return all; + } protected List createFortunes() { List fortuneMessages = IntStream.range(0, 10).boxed().toList(); diff --git a/frameworks/Java/micronaut/common/src/main/java/benchmark/controller/AsyncBenchmarkController.java b/frameworks/Java/micronaut/common/src/main/java/benchmark/controller/AsyncBenchmarkController.java index 7e40c36a204..a16ce1933c3 100644 --- a/frameworks/Java/micronaut/common/src/main/java/benchmark/controller/AsyncBenchmarkController.java +++ b/frameworks/Java/micronaut/common/src/main/java/benchmark/controller/AsyncBenchmarkController.java @@ -5,11 +5,9 @@ import benchmark.repository.AsyncFortuneRepository; import benchmark.repository.AsyncWorldRepository; import io.micronaut.context.annotation.Requires; -import io.micronaut.http.HttpResponse; import io.micronaut.http.annotation.Controller; import io.micronaut.http.annotation.Get; import io.micronaut.http.annotation.QueryValue; -import views.fortunes; import java.util.ArrayList; import java.util.Comparator; @@ -55,15 +53,8 @@ public CompletionStage> queries(@QueryValue String queries) { // https://github.com/TechEmpower/FrameworkBenchmarks/wiki/Project-Information-Framework-Tests-Overview#fortunes @Get(value = "/fortunes", produces = "text/html;charset=utf-8") - public CompletionStage> fortune() { - return fortuneRepository.findAll().thenApply(fortuneList -> { - List all = new ArrayList<>(fortuneList.size() + 1); - all.add(new Fortune(0, "Additional fortune added at request time.")); - all.addAll(fortuneList); - all.sort(comparing(Fortune::message)); - String body = fortunes.template(all).render().toString(); - return HttpResponse.ok(body).contentType("text/html;charset=utf-8"); - }); + public CompletionStage> fortune() { + return fortuneRepository.findAll().thenApply(this::prepareFortunes); } // https://github.com/TechEmpower/FrameworkBenchmarks/wiki/Project-Information-Framework-Tests-Overview#database-updates diff --git a/frameworks/Java/micronaut/common/src/main/java/benchmark/controller/BenchmarkController.java b/frameworks/Java/micronaut/common/src/main/java/benchmark/controller/BenchmarkController.java index c00eed41fb4..f38940257d3 100644 --- a/frameworks/Java/micronaut/common/src/main/java/benchmark/controller/BenchmarkController.java +++ b/frameworks/Java/micronaut/common/src/main/java/benchmark/controller/BenchmarkController.java @@ -5,19 +5,14 @@ import benchmark.repository.FortuneRepository; import benchmark.repository.WorldRepository; import io.micronaut.context.annotation.Requires; -import io.micronaut.http.HttpResponse; import io.micronaut.http.annotation.Controller; import io.micronaut.http.annotation.Get; import io.micronaut.http.annotation.QueryValue; -import views.fortunes; import java.util.ArrayList; -import java.util.Collection; import java.util.Comparator; import java.util.List; -import static java.util.Comparator.comparing; - @Requires(beans = {WorldRepository.class, FortuneRepository.class}) @Controller public class BenchmarkController extends AbstractBenchmarkController { @@ -56,14 +51,8 @@ public List queries(@QueryValue String queries) { // https://github.com/TechEmpower/FrameworkBenchmarks/wiki/Project-Information-Framework-Tests-Overview#fortunes @Get(value = "/fortunes", produces = "text/html;charset=utf-8") - public HttpResponse fortune() { - Collection all = fortuneRepository.findAll(); - List fortunesList = new ArrayList<>(all.size() + 1); - fortunesList.add(new Fortune(0, "Additional fortune added at request time.")); - fortunesList.addAll(all); - fortunesList.sort(comparing(Fortune::message)); - String body = fortunes.template(fortunesList).render().toString(); - return HttpResponse.ok(body).contentType("text/html;charset=utf-8"); + public List fortune() { + return prepareFortunes(fortuneRepository.findAll()); } // https://github.com/TechEmpower/FrameworkBenchmarks/wiki/Project-Information-Framework-Tests-Overview#database-updates @@ -77,5 +66,5 @@ public List updates(@QueryValue String queries) { worldRepository.updateAll(worldList); return worldList; } - + } diff --git a/frameworks/Java/micronaut/common/src/main/java/benchmark/controller/FortunesBodyWriter.java b/frameworks/Java/micronaut/common/src/main/java/benchmark/controller/FortunesBodyWriter.java new file mode 100644 index 00000000000..a7bee37d493 --- /dev/null +++ b/frameworks/Java/micronaut/common/src/main/java/benchmark/controller/FortunesBodyWriter.java @@ -0,0 +1,54 @@ +package benchmark.controller; + +import benchmark.model.Fortune; +import gg.jte.TemplateOutput; +import gg.jte.generated.precompiled.JtefortunesGenerated; +import gg.jte.html.OwaspHtmlTemplateOutput; +import io.micronaut.core.annotation.NonNull; +import io.micronaut.core.type.Argument; +import io.micronaut.core.type.MutableHeaders; +import io.micronaut.http.MediaType; +import io.micronaut.http.body.MessageBodyWriter; +import io.micronaut.http.codec.CodecException; +import io.micronaut.http.netty.NettyHttpHeaders; +import jakarta.inject.Singleton; + +import java.io.IOException; +import java.io.OutputStream; +import java.nio.charset.StandardCharsets; +import java.util.List; + +@Singleton +public class FortunesBodyWriter implements MessageBodyWriter> { + + @Override + public void writeTo(@NonNull Argument> type, + @NonNull MediaType mediaType, + List values, + @NonNull MutableHeaders outgoingHeaders, + @NonNull OutputStream outputStream) throws CodecException { + outgoingHeaders.set(NettyHttpHeaders.CONTENT_TYPE, "text/html;charset=utf-8"); + TemplateOutput output = new TemplateOutput() { + + @Override + public void writeContent(String value) { + writeBinaryContent(value.getBytes(StandardCharsets.UTF_8)); + } + + @Override + public void writeContent(String value, int beginIndex, int endIndex) { + writeBinaryContent(value.substring(beginIndex, endIndex).getBytes(StandardCharsets.UTF_8)); + } + + @Override + public void writeBinaryContent(byte[] value) { + try { + outputStream.write(value); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + }; + JtefortunesGenerated.render(new OwaspHtmlTemplateOutput(output), null, values); + } +} diff --git a/frameworks/Java/micronaut/common/src/main/java/benchmark/controller/ReactiveBenchmarkController.java b/frameworks/Java/micronaut/common/src/main/java/benchmark/controller/ReactiveBenchmarkController.java index 8adbc4c4716..e85d236acee 100644 --- a/frameworks/Java/micronaut/common/src/main/java/benchmark/controller/ReactiveBenchmarkController.java +++ b/frameworks/Java/micronaut/common/src/main/java/benchmark/controller/ReactiveBenchmarkController.java @@ -6,21 +6,17 @@ import benchmark.repository.ReactiveWorldRepository; import io.micronaut.context.annotation.Requires; import io.micronaut.core.async.annotation.SingleResult; -import io.micronaut.http.HttpResponse; import io.micronaut.http.annotation.Controller; import io.micronaut.http.annotation.Get; import io.micronaut.http.annotation.QueryValue; import org.reactivestreams.Publisher; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; -import views.fortunes; import java.util.ArrayList; import java.util.Comparator; import java.util.List; -import static java.util.Comparator.comparing; - @Requires(beans = {ReactiveWorldRepository.class, ReactiveFortuneRepository.class}) @Controller public class ReactiveBenchmarkController extends AbstractBenchmarkController { @@ -61,15 +57,8 @@ public Publisher> queries(@QueryValue String queries) { // https://github.com/TechEmpower/FrameworkBenchmarks/wiki/Project-Information-Framework-Tests-Overview#fortunes @Get(value = "/fortunes", produces = "text/html;charset=utf-8") @SingleResult - public Mono> fortune() { - return Mono.from(fortuneRepository.findAll()).map(fortuneList -> { - List all = new ArrayList<>(fortuneList.size() + 1); - all.add(new Fortune(0, "Additional fortune added at request time.")); - all.addAll(fortuneList); - all.sort(comparing(Fortune::message)); - String body = fortunes.template(all).render().toString(); - return HttpResponse.ok(body).contentType("text/html;charset=utf-8"); - }); + public Mono> fortune() { + return Mono.from(fortuneRepository.findAll()).map(this::prepareFortunes); } // https://github.com/TechEmpower/FrameworkBenchmarks/wiki/Project-Information-Framework-Tests-Overview#database-updates diff --git a/frameworks/Java/micronaut/common/src/main/java/benchmark/repository/FortuneRepository.java b/frameworks/Java/micronaut/common/src/main/java/benchmark/repository/FortuneRepository.java index 701f647e384..b1c8fe3989e 100644 --- a/frameworks/Java/micronaut/common/src/main/java/benchmark/repository/FortuneRepository.java +++ b/frameworks/Java/micronaut/common/src/main/java/benchmark/repository/FortuneRepository.java @@ -4,11 +4,12 @@ import org.reactivestreams.Publisher; import java.util.Collection; +import java.util.List; public interface FortuneRepository { void initDb(Collection fortunes); - Collection findAll(); + List findAll(); } diff --git a/frameworks/Java/micronaut/common/src/main/jte/fortunes.jte b/frameworks/Java/micronaut/common/src/main/jte/fortunes.jte new file mode 100644 index 00000000000..7ac61415c99 --- /dev/null +++ b/frameworks/Java/micronaut/common/src/main/jte/fortunes.jte @@ -0,0 +1,4 @@ +@param java.util.List fortunes +Fortunes@for(benchmark.model.Fortune fortune : fortunes) + @endfor +
idmessage
${fortune.id()}${fortune.message()}
\ No newline at end of file diff --git a/frameworks/Java/micronaut/common/src/main/resources/views/fortunes.rocker.html b/frameworks/Java/micronaut/common/src/main/resources/views/fortunes.rocker.html deleted file mode 100644 index c6b9d0124a6..00000000000 --- a/frameworks/Java/micronaut/common/src/main/resources/views/fortunes.rocker.html +++ /dev/null @@ -1,8 +0,0 @@ -@import java.util.* -@import benchmark.model.* -@args(List fortunes) -Fortunes - @for ((ForIterator i, Fortune fortune) : fortunes) { - - } -
idmessage
@fortune.id()@fortune.message()
\ No newline at end of file diff --git a/frameworks/Java/micronaut/gradle.properties b/frameworks/Java/micronaut/gradle.properties index 22d843f7643..8ce6479ffe6 100644 --- a/frameworks/Java/micronaut/gradle.properties +++ b/frameworks/Java/micronaut/gradle.properties @@ -1 +1 @@ -micronautVersion=4.6.0 +micronautVersion=4.6.1 diff --git a/frameworks/Java/micronaut/micronaut-data-jdbc/src/main/java/benchmark/JdbcWorldRepository.java b/frameworks/Java/micronaut/micronaut-data-jdbc/src/main/java/benchmark/JdbcWorldRepository.java index 3b08db89390..89e9a6be895 100644 --- a/frameworks/Java/micronaut/micronaut-data-jdbc/src/main/java/benchmark/JdbcWorldRepository.java +++ b/frameworks/Java/micronaut/micronaut-data-jdbc/src/main/java/benchmark/JdbcWorldRepository.java @@ -2,6 +2,7 @@ import benchmark.model.World; import benchmark.repository.WorldRepository; +import io.micronaut.data.connection.annotation.Connectable; import io.micronaut.data.jdbc.annotation.JdbcRepository; import io.micronaut.data.model.query.builder.sql.Dialect; import io.micronaut.data.repository.GenericRepository; @@ -20,6 +21,7 @@ default void initDb(Collection worlds) { void saveAll(Collection worlds); + @Connectable @Override default List findByIds(List ids) { return WorldRepository.super.findByIds(ids); diff --git a/frameworks/Java/micronaut/micronaut-graalvm.dockerfile b/frameworks/Java/micronaut/micronaut-graalvm.dockerfile index 0b45b87f1dc..c1e1207fa96 100644 --- a/frameworks/Java/micronaut/micronaut-graalvm.dockerfile +++ b/frameworks/Java/micronaut/micronaut-graalvm.dockerfile @@ -1,4 +1,4 @@ -FROM container-registry.oracle.com/graalvm/native-image:21 +FROM container-registry.oracle.com/graalvm/native-image:22 RUN microdnf install findutils # Gradle 8.7 requires xargs COPY . /home/gradle/src WORKDIR /home/gradle/src diff --git a/frameworks/Java/micronaut/micronaut-jdbc-graalvm.dockerfile b/frameworks/Java/micronaut/micronaut-jdbc-graalvm.dockerfile index ceae0bdf03e..6b6e9262aa2 100644 --- a/frameworks/Java/micronaut/micronaut-jdbc-graalvm.dockerfile +++ b/frameworks/Java/micronaut/micronaut-jdbc-graalvm.dockerfile @@ -1,4 +1,4 @@ -FROM container-registry.oracle.com/graalvm/native-image:21 +FROM container-registry.oracle.com/graalvm/native-image:22 RUN microdnf install findutils # Gradle 8.7 requires xargs COPY . /home/gradle/src WORKDIR /home/gradle/src diff --git a/frameworks/Java/micronaut/micronaut-jdbc/src/main/java/benchmark/JdbcFortuneRepository.java b/frameworks/Java/micronaut/micronaut-jdbc/src/main/java/benchmark/JdbcFortuneRepository.java index 8b07fd1c6fc..2315804f7c2 100644 --- a/frameworks/Java/micronaut/micronaut-jdbc/src/main/java/benchmark/JdbcFortuneRepository.java +++ b/frameworks/Java/micronaut/micronaut-jdbc/src/main/java/benchmark/JdbcFortuneRepository.java @@ -42,7 +42,7 @@ public void initDb(Collection fortunes) { } @Override - public Collection findAll() { + public List findAll() { try (Connection connection = dataSource.getConnection()) { try (PreparedStatement statement = connection.prepareStatement("SELECT id, message FROM fortune", ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY)) { diff --git a/frameworks/Java/micronaut/micronaut-r2dbc-graalvm.dockerfile b/frameworks/Java/micronaut/micronaut-r2dbc-graalvm.dockerfile index 574496a0b91..06ccaea922c 100644 --- a/frameworks/Java/micronaut/micronaut-r2dbc-graalvm.dockerfile +++ b/frameworks/Java/micronaut/micronaut-r2dbc-graalvm.dockerfile @@ -1,4 +1,4 @@ -FROM container-registry.oracle.com/graalvm/native-image:21 +FROM container-registry.oracle.com/graalvm/native-image:22 RUN microdnf install findutils # Gradle 8.7 requires xargs COPY . /home/gradle/src WORKDIR /home/gradle/src From b87e736d3f2e1ff55b066c29bc55232852bba133 Mon Sep 17 00:00:00 2001 From: Juanjo Aguililla Date: Thu, 19 Sep 2024 16:17:08 +0200 Subject: [PATCH 119/204] [Kotlin/Hexagon] Update Hexagon toolkit release (#9284) * Chores * Fix template loading error * Delete MongoDB DB support Storage support in Hexagon will be moved outside the Toolkit, and so, it will be left outside the benchmark. * Fix runtime problem * Update Hexagon version * Make Jackson Blackbird module optional * Add variation with Blackbird module enabled * Upgrade Hexagon version * Enable blackbird Jackson module by default * Update dependencies * Use Hexagon version 2.0.0-B1 (and a little cleanup) * Use Hexagon version 2.0.0-B1 (and a little cleanup) * Use Tomcat instead Resin to test JEE integration * Remove unused environment variable * Clean Tomcat dockerfile * Minor improvements * Minor improvements * Update to release version * Update to the latest Hexagon release * Add Netty adapter test * Remove Gradle Wrapper * Update version * Update version * Minimize template * Skip Hexagon checks in the container * Add Netty Epoll benchmark * Database and template improvements * Update Hexagon version * Update Hexagon version * Update DB settings * Use a single store and template engine to simplify benchmark * Bump mysql-connector-java in /frameworks/Java/wicket Bumps [mysql-connector-java](https://github.com/mysql/mysql-connector-j) from 8.0.27 to 8.0.28. - [Release notes](https://github.com/mysql/mysql-connector-j/releases) - [Changelog](https://github.com/mysql/mysql-connector-j/blob/release/8.0/CHANGES) - [Commits](https://github.com/mysql/mysql-connector-j/compare/8.0.27...8.0.28) --- updated-dependencies: - dependency-name: mysql:mysql-connector-java dependency-type: direct:production ... Signed-off-by: dependabot[bot] * Bump mongodb-driver-sync from 4.2.0 to 4.2.1 in /frameworks/Java/javalin Bumps [mongodb-driver-sync](https://github.com/mongodb/mongo-java-driver) from 4.2.0 to 4.2.1. - [Release notes](https://github.com/mongodb/mongo-java-driver/releases) - [Commits](https://github.com/mongodb/mongo-java-driver/compare/r4.2.0...r4.2.1) --- updated-dependencies: - dependency-name: org.mongodb:mongodb-driver-sync dependency-type: direct:production ... Signed-off-by: dependabot[bot] * Bump ujson from 5.2.0 to 5.4.0 in /frameworks/Python/starlette Bumps [ujson](https://github.com/ultrajson/ultrajson) from 5.2.0 to 5.4.0. - [Release notes](https://github.com/ultrajson/ultrajson/releases) - [Commits](https://github.com/ultrajson/ultrajson/compare/5.2.0...5.4.0) --- updated-dependencies: - dependency-name: ujson dependency-type: direct:production ... Signed-off-by: dependabot[bot] * Bump ujson from 5.2.0 to 5.4.0 in /frameworks/Python/django Bumps [ujson](https://github.com/ultrajson/ultrajson) from 5.2.0 to 5.4.0. - [Release notes](https://github.com/ultrajson/ultrajson/releases) - [Commits](https://github.com/ultrajson/ultrajson/compare/5.2.0...5.4.0) --- updated-dependencies: - dependency-name: ujson dependency-type: direct:production ... Signed-off-by: dependabot[bot] * Bump ujson from 5.2.0 to 5.4.0 in /frameworks/Python/routerling Bumps [ujson](https://github.com/ultrajson/ultrajson) from 5.2.0 to 5.4.0. - [Release notes](https://github.com/ultrajson/ultrajson/releases) - [Commits](https://github.com/ultrajson/ultrajson/compare/5.2.0...5.4.0) --- updated-dependencies: - dependency-name: ujson dependency-type: direct:production ... Signed-off-by: dependabot[bot] * Bump ujson from 5.2.0 to 5.4.0 in /frameworks/Python/japronto Bumps [ujson](https://github.com/ultrajson/ultrajson) from 5.2.0 to 5.4.0. - [Release notes](https://github.com/ultrajson/ultrajson/releases) - [Commits](https://github.com/ultrajson/ultrajson/compare/5.2.0...5.4.0) --- updated-dependencies: - dependency-name: ujson dependency-type: direct:production ... Signed-off-by: dependabot[bot] * Bump ujson from 5.2.0 to 5.4.0 in /frameworks/Python/fastapi Bumps [ujson](https://github.com/ultrajson/ultrajson) from 5.2.0 to 5.4.0. - [Release notes](https://github.com/ultrajson/ultrajson/releases) - [Commits](https://github.com/ultrajson/ultrajson/compare/5.2.0...5.4.0) --- updated-dependencies: - dependency-name: ujson dependency-type: direct:production ... Signed-off-by: dependabot[bot] * Bump ujson from 5.2.0 to 5.4.0 in /frameworks/Python/uvicorn Bumps [ujson](https://github.com/ultrajson/ultrajson) from 5.2.0 to 5.4.0. - [Release notes](https://github.com/ultrajson/ultrajson/releases) - [Commits](https://github.com/ultrajson/ultrajson/compare/5.2.0...5.4.0) --- updated-dependencies: - dependency-name: ujson dependency-type: direct:production ... Signed-off-by: dependabot[bot] * Bump ujson from 5.2.0 to 5.4.0 in /frameworks/Python/flask Bumps [ujson](https://github.com/ultrajson/ultrajson) from 5.2.0 to 5.4.0. - [Release notes](https://github.com/ultrajson/ultrajson/releases) - [Commits](https://github.com/ultrajson/ultrajson/compare/5.2.0...5.4.0) --- updated-dependencies: - dependency-name: ujson dependency-type: direct:production ... Signed-off-by: dependabot[bot] * Bump ujson from 5.1 to 5.4.0 in /frameworks/Python/aiohttp Bumps [ujson](https://github.com/ultrajson/ultrajson) from 5.1 to 5.4.0. - [Release notes](https://github.com/ultrajson/ultrajson/releases) - [Commits](https://github.com/ultrajson/ultrajson/compare/5.1.0...5.4.0) --- updated-dependencies: - dependency-name: ujson dependency-type: direct:production ... Signed-off-by: dependabot[bot] * Bump rails-html-sanitizer from 1.4.2 to 1.4.3 in /frameworks/Ruby/rails Bumps [rails-html-sanitizer](https://github.com/rails/rails-html-sanitizer) from 1.4.2 to 1.4.3. - [Release notes](https://github.com/rails/rails-html-sanitizer/releases) - [Changelog](https://github.com/rails/rails-html-sanitizer/blob/master/CHANGELOG.md) - [Commits](https://github.com/rails/rails-html-sanitizer/compare/v1.4.2...v1.4.3) --- updated-dependencies: - dependency-name: rails-html-sanitizer dependency-type: indirect ... Signed-off-by: dependabot[bot] * Bump jetty-server in /frameworks/Java/jetty Bumps [jetty-server](https://github.com/eclipse/jetty.project) from 9.4.41.v20210516 to 10.0.10. - [Release notes](https://github.com/eclipse/jetty.project/releases) - [Commits](https://github.com/eclipse/jetty.project/compare/jetty-9.4.41.v20210516...jetty-10.0.10) --- updated-dependencies: - dependency-name: org.eclipse.jetty:jetty-server dependency-type: direct:production ... Signed-off-by: dependabot[bot] * Bump undertow-core in /frameworks/Java/undertow Bumps [undertow-core](https://github.com/undertow-io/undertow) from 2.2.11.Final to 2.2.15.Final. - [Release notes](https://github.com/undertow-io/undertow/releases) - [Commits](https://github.com/undertow-io/undertow/compare/2.2.11.Final...2.2.15.Final) --- updated-dependencies: - dependency-name: io.undertow:undertow-core dependency-type: direct:production ... Signed-off-by: dependabot[bot] * Update versions * Update README.md * Bump sanic from 22.3.1 to 22.6.1 in /frameworks/Python/sanic Bumps [sanic](https://github.com/sanic-org/sanic) from 22.3.1 to 22.6.1. - [Release notes](https://github.com/sanic-org/sanic/releases) - [Changelog](https://github.com/sanic-org/sanic/blob/main/CHANGELOG.rst) - [Commits](https://github.com/sanic-org/sanic/compare/v22.3.1...v22.6.1) --- updated-dependencies: - dependency-name: sanic dependency-type: direct:production ... Signed-off-by: dependabot[bot] * Bump postgresql from 42.3.3 to 42.4.1 in /frameworks/Java/light-java Bumps [postgresql](https://github.com/pgjdbc/pgjdbc) from 42.3.3 to 42.4.1. - [Release notes](https://github.com/pgjdbc/pgjdbc/releases) - [Changelog](https://github.com/pgjdbc/pgjdbc/blob/master/CHANGELOG.md) - [Commits](https://github.com/pgjdbc/pgjdbc/compare/REL42.3.3...REL42.4.1) --- updated-dependencies: - dependency-name: org.postgresql:postgresql dependency-type: direct:production ... Signed-off-by: dependabot[bot] * Bump postgresql from 42.3.3 to 42.4.1 in /frameworks/Java/rapidoid Bumps [postgresql](https://github.com/pgjdbc/pgjdbc) from 42.3.3 to 42.4.1. - [Release notes](https://github.com/pgjdbc/pgjdbc/releases) - [Changelog](https://github.com/pgjdbc/pgjdbc/blob/master/CHANGELOG.md) - [Commits](https://github.com/pgjdbc/pgjdbc/compare/REL42.3.3...REL42.4.1) --- updated-dependencies: - dependency-name: org.postgresql:postgresql dependency-type: direct:production ... Signed-off-by: dependabot[bot] * Bump postgresql from 42.3.3 to 42.4.1 in /frameworks/Java/jooby Bumps [postgresql](https://github.com/pgjdbc/pgjdbc) from 42.3.3 to 42.4.1. - [Release notes](https://github.com/pgjdbc/pgjdbc/releases) - [Changelog](https://github.com/pgjdbc/pgjdbc/blob/master/CHANGELOG.md) - [Commits](https://github.com/pgjdbc/pgjdbc/compare/REL42.3.3...REL42.4.1) --- updated-dependencies: - dependency-name: org.postgresql:postgresql dependency-type: direct:production ... Signed-off-by: dependabot[bot] * Bump postgresql from 42.3.3 to 42.4.1 in /frameworks/Java/servlet Bumps [postgresql](https://github.com/pgjdbc/pgjdbc) from 42.3.3 to 42.4.1. - [Release notes](https://github.com/pgjdbc/pgjdbc/releases) - [Changelog](https://github.com/pgjdbc/pgjdbc/blob/master/CHANGELOG.md) - [Commits](https://github.com/pgjdbc/pgjdbc/compare/REL42.3.3...REL42.4.1) --- updated-dependencies: - dependency-name: org.postgresql:postgresql dependency-type: direct:production ... Signed-off-by: dependabot[bot] * Bump postgresql from 42.3.3 to 42.4.1 in /frameworks/Java/spring-webflux Bumps [postgresql](https://github.com/pgjdbc/pgjdbc) from 42.3.3 to 42.4.1. - [Release notes](https://github.com/pgjdbc/pgjdbc/releases) - [Changelog](https://github.com/pgjdbc/pgjdbc/blob/master/CHANGELOG.md) - [Commits](https://github.com/pgjdbc/pgjdbc/compare/REL42.3.3...REL42.4.1) --- updated-dependencies: - dependency-name: org.postgresql:postgresql dependency-type: direct:production ... Signed-off-by: dependabot[bot] * Bump postgresql from 42.3.3 to 42.4.1 in /frameworks/Java/smart-socket Bumps [postgresql](https://github.com/pgjdbc/pgjdbc) from 42.3.3 to 42.4.1. - [Release notes](https://github.com/pgjdbc/pgjdbc/releases) - [Changelog](https://github.com/pgjdbc/pgjdbc/blob/master/CHANGELOG.md) - [Commits](https://github.com/pgjdbc/pgjdbc/compare/REL42.3.3...REL42.4.1) --- updated-dependencies: - dependency-name: org.postgresql:postgresql dependency-type: direct:production ... Signed-off-by: dependabot[bot] * Bump postgresql from 42.3.3 to 42.4.1 in /frameworks/Java/act Bumps [postgresql](https://github.com/pgjdbc/pgjdbc) from 42.3.3 to 42.4.1. - [Release notes](https://github.com/pgjdbc/pgjdbc/releases) - [Changelog](https://github.com/pgjdbc/pgjdbc/blob/master/CHANGELOG.md) - [Commits](https://github.com/pgjdbc/pgjdbc/compare/REL42.3.3...REL42.4.1) --- updated-dependencies: - dependency-name: org.postgresql:postgresql dependency-type: direct:production ... Signed-off-by: dependabot[bot] * Bump postgresql from 42.3.3 to 42.4.1 in /frameworks/Kotlin/kooby Bumps [postgresql](https://github.com/pgjdbc/pgjdbc) from 42.3.3 to 42.4.1. - [Release notes](https://github.com/pgjdbc/pgjdbc/releases) - [Changelog](https://github.com/pgjdbc/pgjdbc/blob/master/CHANGELOG.md) - [Commits](https://github.com/pgjdbc/pgjdbc/compare/REL42.3.3...REL42.4.1) --- updated-dependencies: - dependency-name: org.postgresql:postgresql dependency-type: direct:production ... Signed-off-by: dependabot[bot] * Bump postgresql from 42.3.3 to 42.4.1 in /frameworks/Java/dropwizard Bumps [postgresql](https://github.com/pgjdbc/pgjdbc) from 42.3.3 to 42.4.1. - [Release notes](https://github.com/pgjdbc/pgjdbc/releases) - [Changelog](https://github.com/pgjdbc/pgjdbc/blob/master/CHANGELOG.md) - [Commits](https://github.com/pgjdbc/pgjdbc/compare/REL42.3.3...REL42.4.1) --- updated-dependencies: - dependency-name: org.postgresql:postgresql dependency-type: direct:production ... Signed-off-by: dependabot[bot] * Bump postgresql from 42.3.3 to 42.4.1 in /frameworks/Java/hserver Bumps [postgresql](https://github.com/pgjdbc/pgjdbc) from 42.3.3 to 42.4.1. - [Release notes](https://github.com/pgjdbc/pgjdbc/releases) - [Changelog](https://github.com/pgjdbc/pgjdbc/blob/master/CHANGELOG.md) - [Commits](https://github.com/pgjdbc/pgjdbc/compare/REL42.3.3...REL42.4.1) --- updated-dependencies: - dependency-name: org.postgresql:postgresql dependency-type: direct:production ... Signed-off-by: dependabot[bot] * Bump postgresql from 42.4.0 to 42.4.1 in /frameworks/Java/undertow Bumps [postgresql](https://github.com/pgjdbc/pgjdbc) from 42.4.0 to 42.4.1. - [Release notes](https://github.com/pgjdbc/pgjdbc/releases) - [Changelog](https://github.com/pgjdbc/pgjdbc/blob/master/CHANGELOG.md) - [Commits](https://github.com/pgjdbc/pgjdbc/compare/REL42.4.0...REL42.4.1) --- updated-dependencies: - dependency-name: org.postgresql:postgresql dependency-type: direct:production ... Signed-off-by: dependabot[bot] * Bump postgresql from 42.2.23 to 42.4.1 in /frameworks/Kotlin/ktor/ktor Bumps [postgresql](https://github.com/pgjdbc/pgjdbc) from 42.2.23 to 42.4.1. - [Release notes](https://github.com/pgjdbc/pgjdbc/releases) - [Changelog](https://github.com/pgjdbc/pgjdbc/blob/master/CHANGELOG.md) - [Commits](https://github.com/pgjdbc/pgjdbc/compare/REL42.2.23...REL42.4.1) --- updated-dependencies: - dependency-name: org.postgresql:postgresql dependency-type: direct:production ... Signed-off-by: dependabot[bot] * Update dependencies * Bump undertow-core in /frameworks/Java/light-java Bumps [undertow-core](https://github.com/undertow-io/undertow) from 2.2.15.Final to 2.2.19.Final. - [Release notes](https://github.com/undertow-io/undertow/releases) - [Commits](https://github.com/undertow-io/undertow/compare/2.2.15.Final...2.2.19.Final) --- updated-dependencies: - dependency-name: io.undertow:undertow-core dependency-type: direct:production ... Signed-off-by: dependabot[bot] * Bump undertow-core in /frameworks/Java/undertow Bumps [undertow-core](https://github.com/undertow-io/undertow) from 2.2.18.Final to 2.2.19.Final. - [Release notes](https://github.com/undertow-io/undertow/releases) - [Commits](https://github.com/undertow-io/undertow/compare/2.2.18.Final...2.2.19.Final) --- updated-dependencies: - dependency-name: io.undertow:undertow-core dependency-type: direct:production ... Signed-off-by: dependabot[bot] * Delete Gradle Wrapper * Use different JSON serializer * Restore non Hexagon files * Update Hexagon version * Run pipeline * Run pipeline * Bump axum-core from 0.2.7 to 0.2.8 in /frameworks/Rust/axum Bumps [axum-core](https://github.com/tokio-rs/axum) from 0.2.7 to 0.2.8. - [Release notes](https://github.com/tokio-rs/axum/releases) - [Changelog](https://github.com/tokio-rs/axum/blob/main/CHANGELOG.md) - [Commits](https://github.com/tokio-rs/axum/compare/axum-core-v0.2.7...axum-core-v0.2.8) --- updated-dependencies: - dependency-name: axum-core dependency-type: indirect ... Signed-off-by: dependabot[bot] * Revert "Bump axum-core from 0.2.7 to 0.2.8 in /frameworks/Rust/axum" This reverts commit 4422de8915e70cdca67a07c2e0fdb0610757924b. * Version updates, code refactor and new benchmark cases * Version updates * Version updates * Version updates * [Hexagon] Refactor and updates: * Update Hexagon version * Use Rocker template * Modularize the different scenarios * Fix connection problems * Update Hexagon * Update Gradle * Update dependencies * Update Hexagon version * Update Gradle Wrapper * Add async and native support * Add async and native support * Add async and native support * Replace Vert.x adapter by Netty Epoll Async adapter * Replace Vert.x adapter by Netty Epoll Async adapter * Replace Vert.x adapter by Netty Epoll Async adapter * Replace Vert.x adapter by Netty Epoll Async adapter * Replace Vert.x adapter by Netty Epoll Async adapter * Add Jasync store * Add Jasync store * Update * Update * Update * Update Gradle * Benchmark Netty Epoll only * Add Nima adapter * Update container builds * Fix missing endpoints * Fix Nima benchmarks * Update dependencies * Update dependencies * Update dependencies * Fix build * Fix controller * Fix native tests * Fix native tests * Add note * Add note * Update dependencies * Update dependencies * Update dependencies * Recheck CI jobs * Update dependencies * Update dependencies * Update dependencies * Update dependencies * Update dependencies * Update dependencies * Update Hexagon and Java version, switch templates to JTE * Update Hexagon and improve Netty Epoll configuration * Update Hexagon version * Update dependencies * Update dependencies * Update dependencies * Update dependencies * Update dependencies * Update dependencies * Update dependencies * Update dependencies * Update dependencies * Update dependencies * Update dependencies * Update dependencies * Update dependencies * Update Hexagon version * Update dependencies * Update dependencies and change settings * Update dependencies and change settings --------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- frameworks/Kotlin/hexagon/build.gradle | 16 ++++++++-------- .../hexagon/gradle/wrapper/gradle-wrapper.jar | Bin 43462 -> 43504 bytes .../gradle/wrapper/gradle-wrapper.properties | 2 +- frameworks/Kotlin/hexagon/gradlew | 7 +++++-- frameworks/Kotlin/hexagon/gradlew.bat | 2 ++ .../hexagon/hexagon-helidon-native.dockerfile | 2 ++ .../hexagon-helidon-pgclient.dockerfile | 9 +++++---- .../Kotlin/hexagon/hexagon-helidon.dockerfile | 9 +++++---- .../hexagon/hexagon-jetty-native.dockerfile | 2 ++ .../hexagon-jettyloom-pgclient.dockerfile | 7 ++++--- .../hexagon/hexagon-jettyloom.dockerfile | 7 ++++--- .../hexagon-nettyepoll-pgclient.dockerfile | 7 ++++--- .../hexagon/hexagon-nettyepoll.dockerfile | 7 ++++--- .../Kotlin/hexagon/hexagon-tomcat.dockerfile | 7 ++++--- frameworks/Kotlin/hexagon/hexagon.dockerfile | 7 ++++--- .../src/main/kotlin/Benchmark.kt | 18 +++++++++++++++--- .../src/main/kotlin/BenchmarkPgClientStore.kt | 12 +++++++++--- 17 files changed, 78 insertions(+), 43 deletions(-) diff --git a/frameworks/Kotlin/hexagon/build.gradle b/frameworks/Kotlin/hexagon/build.gradle index a4d141e5c2a..d1f77b2b178 100644 --- a/frameworks/Kotlin/hexagon/build.gradle +++ b/frameworks/Kotlin/hexagon/build.gradle @@ -1,7 +1,7 @@ plugins { - id "org.jetbrains.kotlin.jvm" version "2.0.20-RC" apply false - id "org.graalvm.buildtools.native" version "0.10.2" apply false + id "org.jetbrains.kotlin.jvm" version "2.0.20" apply false + id "org.graalvm.buildtools.native" version "0.10.3" apply false } version = "1.0.0" @@ -9,13 +9,13 @@ description = "TFB benchmark" group = "com.hexagonkt" ext { - hexagonVersion = "3.6.1" - jettyVersion = "12.0.12" - nettyVersion = "4.1.112.Final" + hexagonVersion = "3.7.0" + jettyVersion = "12.0.13" + nettyVersion = "4.1.113.Final" hikariVersion = "5.1.0" - postgresqlVersion = "42.7.3" - vertxVersion = "4.5.9" + postgresqlVersion = "42.7.4" + vertxVersion = "4.5.10" cache2kVersion = "2.6.1.Final" applicationClass = "com.hexagonkt.BenchmarkKt" @@ -30,5 +30,5 @@ subprojects { } tasks.wrapper { - gradleVersion = "8.9" + gradleVersion = "8.10" } diff --git a/frameworks/Kotlin/hexagon/gradle/wrapper/gradle-wrapper.jar b/frameworks/Kotlin/hexagon/gradle/wrapper/gradle-wrapper.jar index d64cd4917707c1f8861d8cb53dd15194d4248596..2c3521197d7c4586c843d1d3e9090525f1898cde 100644 GIT binary patch delta 34463 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 SXRcJ{65?fGI57uQ5&!`B?F@7P delta 34554 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 diff --git a/frameworks/Kotlin/hexagon/gradle/wrapper/gradle-wrapper.properties b/frameworks/Kotlin/hexagon/gradle/wrapper/gradle-wrapper.properties index 09523c0e549..9355b415575 100644 --- a/frameworks/Kotlin/hexagon/gradle/wrapper/gradle-wrapper.properties +++ b/frameworks/Kotlin/hexagon/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.10-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/frameworks/Kotlin/hexagon/gradlew b/frameworks/Kotlin/hexagon/gradlew index 1aa94a42690..f5feea6d6b1 100755 --- a/frameworks/Kotlin/hexagon/gradlew +++ b/frameworks/Kotlin/hexagon/gradlew @@ -15,6 +15,8 @@ # See the License for the specific language governing permissions and # limitations under the License. # +# SPDX-License-Identifier: Apache-2.0 +# ############################################################################## # @@ -55,7 +57,7 @@ # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template -# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. @@ -84,7 +86,8 @@ done # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) -APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit +APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s +' "$PWD" ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum diff --git a/frameworks/Kotlin/hexagon/gradlew.bat b/frameworks/Kotlin/hexagon/gradlew.bat index 25da30dbdee..9d21a21834d 100644 --- a/frameworks/Kotlin/hexagon/gradlew.bat +++ b/frameworks/Kotlin/hexagon/gradlew.bat @@ -13,6 +13,8 @@ @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem +@rem SPDX-License-Identifier: Apache-2.0 +@rem @if "%DEBUG%"=="" @echo off @rem ########################################################################## diff --git a/frameworks/Kotlin/hexagon/hexagon-helidon-native.dockerfile b/frameworks/Kotlin/hexagon/hexagon-helidon-native.dockerfile index c402f0ee792..25a78904f79 100644 --- a/frameworks/Kotlin/hexagon/hexagon-helidon-native.dockerfile +++ b/frameworks/Kotlin/hexagon/hexagon-helidon-native.dockerfile @@ -16,6 +16,8 @@ RUN ./gradlew --quiet -x test hexagon_helidon_pgclient:nativeCompile FROM scratch ARG PROJECT=hexagon_helidon_pgclient +ENV maximumPoolSize 300 + COPY --from=build /hexagon/$PROJECT/build/native/nativeCompile/$PROJECT / ENTRYPOINT [ "/hexagon_helidon_pgclient" ] diff --git a/frameworks/Kotlin/hexagon/hexagon-helidon-pgclient.dockerfile b/frameworks/Kotlin/hexagon/hexagon-helidon-pgclient.dockerfile index 3b3a1602f55..f11c4e7b2bd 100644 --- a/frameworks/Kotlin/hexagon/hexagon-helidon-pgclient.dockerfile +++ b/frameworks/Kotlin/hexagon/hexagon-helidon-pgclient.dockerfile @@ -1,22 +1,23 @@ # # BUILD # -FROM docker.io/gradle:8.9-jdk21-alpine AS build +FROM docker.io/bellsoft/liberica-runtime-container:jdk-all-22-cds-musl AS build USER root WORKDIR /hexagon ADD . . -RUN gradle --quiet classes -RUN gradle --quiet -x test installDist +RUN ./gradlew --quiet classes +RUN ./gradlew --quiet -x test installDist # # RUNTIME # -FROM docker.io/bellsoft/liberica-runtime-container:jre-21-musl +FROM docker.io/bellsoft/liberica-runtime-container:jre-22-musl ARG PROJECT=hexagon_helidon_pgclient ENV POSTGRESQL_DB_HOST tfb-database ENV JDK_JAVA_OPTIONS --enable-preview -XX:+AlwaysPreTouch -XX:+UseParallelGC -XX:+UseNUMA +ENV maximumPoolSize 300 COPY --from=build /hexagon/$PROJECT/build/install/$PROJECT /opt/$PROJECT diff --git a/frameworks/Kotlin/hexagon/hexagon-helidon.dockerfile b/frameworks/Kotlin/hexagon/hexagon-helidon.dockerfile index 271fa95dbf8..27177de5eb9 100644 --- a/frameworks/Kotlin/hexagon/hexagon-helidon.dockerfile +++ b/frameworks/Kotlin/hexagon/hexagon-helidon.dockerfile @@ -1,22 +1,23 @@ # # BUILD # -FROM docker.io/gradle:8.9-jdk21-alpine AS build +FROM docker.io/bellsoft/liberica-runtime-container:jdk-all-22-cds-musl AS build USER root WORKDIR /hexagon ADD . . -RUN gradle --quiet classes -RUN gradle --quiet -x test installDist +RUN ./gradlew --quiet classes +RUN ./gradlew --quiet -x test installDist # # RUNTIME # -FROM docker.io/bellsoft/liberica-runtime-container:jre-21-musl +FROM docker.io/bellsoft/liberica-runtime-container:jre-22-musl ARG PROJECT=hexagon_helidon_postgresql ENV POSTGRESQL_DB_HOST tfb-database ENV JDK_JAVA_OPTIONS --enable-preview -XX:+AlwaysPreTouch -XX:+UseParallelGC -XX:+UseNUMA +ENV maximumPoolSize 300 COPY --from=build /hexagon/$PROJECT/build/install/$PROJECT /opt/$PROJECT diff --git a/frameworks/Kotlin/hexagon/hexagon-jetty-native.dockerfile b/frameworks/Kotlin/hexagon/hexagon-jetty-native.dockerfile index 2919fdba8b7..b8efc965eb3 100644 --- a/frameworks/Kotlin/hexagon/hexagon-jetty-native.dockerfile +++ b/frameworks/Kotlin/hexagon/hexagon-jetty-native.dockerfile @@ -16,6 +16,8 @@ RUN ./gradlew --quiet -x test hexagon_jetty_postgresql:nativeCompile FROM scratch ARG PROJECT=hexagon_jetty_postgresql +ENV maximumPoolSize 300 + COPY --from=build /hexagon/$PROJECT/build/native/nativeCompile/$PROJECT / ENTRYPOINT [ "/hexagon_jetty_postgresql" ] diff --git a/frameworks/Kotlin/hexagon/hexagon-jettyloom-pgclient.dockerfile b/frameworks/Kotlin/hexagon/hexagon-jettyloom-pgclient.dockerfile index d6c37bcd77f..21ef3b64c8b 100644 --- a/frameworks/Kotlin/hexagon/hexagon-jettyloom-pgclient.dockerfile +++ b/frameworks/Kotlin/hexagon/hexagon-jettyloom-pgclient.dockerfile @@ -1,13 +1,13 @@ # # BUILD # -FROM docker.io/gradle:8.9-jdk21-alpine AS build +FROM docker.io/bellsoft/liberica-runtime-container:jdk-all-21-cds-musl AS build USER root WORKDIR /hexagon ADD . . -RUN gradle --quiet classes -RUN gradle --quiet -x test installDist +RUN ./gradlew --quiet classes +RUN ./gradlew --quiet -x test installDist # # RUNTIME @@ -17,6 +17,7 @@ ARG PROJECT=hexagon_jetty_pgclient ENV POSTGRESQL_DB_HOST tfb-database ENV JDK_JAVA_OPTIONS --enable-preview -XX:+AlwaysPreTouch -XX:+UseParallelGC -XX:+UseNUMA -DvirtualThreads=true +ENV maximumPoolSize 300 COPY --from=build /hexagon/$PROJECT/build/install/$PROJECT /opt/$PROJECT diff --git a/frameworks/Kotlin/hexagon/hexagon-jettyloom.dockerfile b/frameworks/Kotlin/hexagon/hexagon-jettyloom.dockerfile index 07bf482b28e..c51c03bc6db 100644 --- a/frameworks/Kotlin/hexagon/hexagon-jettyloom.dockerfile +++ b/frameworks/Kotlin/hexagon/hexagon-jettyloom.dockerfile @@ -1,13 +1,13 @@ # # BUILD # -FROM docker.io/gradle:8.9-jdk21-alpine AS build +FROM docker.io/bellsoft/liberica-runtime-container:jdk-all-21-cds-musl AS build USER root WORKDIR /hexagon ADD . . -RUN gradle --quiet classes -RUN gradle --quiet -x test installDist +RUN ./gradlew --quiet classes +RUN ./gradlew --quiet -x test installDist # # RUNTIME @@ -17,6 +17,7 @@ ARG PROJECT=hexagon_jetty_postgresql ENV POSTGRESQL_DB_HOST tfb-database ENV JDK_JAVA_OPTIONS --enable-preview -XX:+AlwaysPreTouch -XX:+UseParallelGC -XX:+UseNUMA -DvirtualThreads=true +ENV maximumPoolSize 300 COPY --from=build /hexagon/$PROJECT/build/install/$PROJECT /opt/$PROJECT diff --git a/frameworks/Kotlin/hexagon/hexagon-nettyepoll-pgclient.dockerfile b/frameworks/Kotlin/hexagon/hexagon-nettyepoll-pgclient.dockerfile index 972347f053b..90c5a0d03c8 100644 --- a/frameworks/Kotlin/hexagon/hexagon-nettyepoll-pgclient.dockerfile +++ b/frameworks/Kotlin/hexagon/hexagon-nettyepoll-pgclient.dockerfile @@ -1,13 +1,13 @@ # # BUILD # -FROM docker.io/gradle:8.9-jdk21-alpine AS build +FROM docker.io/bellsoft/liberica-runtime-container:jdk-all-21-cds-musl AS build USER root WORKDIR /hexagon ADD . . -RUN gradle --quiet classes -RUN gradle --quiet -x test installDist +RUN ./gradlew --quiet classes +RUN ./gradlew --quiet -x test installDist # # RUNTIME @@ -17,6 +17,7 @@ ARG PROJECT=hexagon_nettyepoll_pgclient ENV POSTGRESQL_DB_HOST tfb-database ENV JDK_JAVA_OPTIONS -XX:+AlwaysPreTouch -XX:+UseParallelGC -XX:+UseNUMA +ENV maximumPoolSize 300 COPY --from=build /hexagon/$PROJECT/build/install/$PROJECT /opt/$PROJECT diff --git a/frameworks/Kotlin/hexagon/hexagon-nettyepoll.dockerfile b/frameworks/Kotlin/hexagon/hexagon-nettyepoll.dockerfile index 393f73f62a6..35a0e4729b7 100644 --- a/frameworks/Kotlin/hexagon/hexagon-nettyepoll.dockerfile +++ b/frameworks/Kotlin/hexagon/hexagon-nettyepoll.dockerfile @@ -1,13 +1,13 @@ # # BUILD # -FROM docker.io/gradle:8.9-jdk21-alpine AS build +FROM docker.io/bellsoft/liberica-runtime-container:jdk-all-21-cds-musl AS build USER root WORKDIR /hexagon ADD . . -RUN gradle --quiet classes -RUN gradle --quiet -x test installDist +RUN ./gradlew --quiet classes +RUN ./gradlew --quiet -x test installDist # # RUNTIME @@ -17,6 +17,7 @@ ARG PROJECT=hexagon_nettyepoll_postgresql ENV POSTGRESQL_DB_HOST tfb-database ENV JDK_JAVA_OPTIONS -XX:+AlwaysPreTouch -XX:+UseParallelGC -XX:+UseNUMA +ENV maximumPoolSize 300 COPY --from=build /hexagon/$PROJECT/build/install/$PROJECT /opt/$PROJECT diff --git a/frameworks/Kotlin/hexagon/hexagon-tomcat.dockerfile b/frameworks/Kotlin/hexagon/hexagon-tomcat.dockerfile index 32e153cbc0a..42f28071128 100644 --- a/frameworks/Kotlin/hexagon/hexagon-tomcat.dockerfile +++ b/frameworks/Kotlin/hexagon/hexagon-tomcat.dockerfile @@ -1,13 +1,13 @@ # # BUILD # -FROM docker.io/gradle:8.9-jdk21-alpine AS build +FROM docker.io/bellsoft/liberica-runtime-container:jdk-all-21-cds-musl AS build USER root WORKDIR /hexagon ADD . . -RUN gradle --quiet classes -RUN gradle --quiet -x test war +RUN ./gradlew --quiet classes +RUN ./gradlew --quiet -x test war # # RUNTIME @@ -17,5 +17,6 @@ ARG MODULE=/hexagon/hexagon_tomcat_postgresql ENV POSTGRESQL_DB_HOST tfb-database ENV JDK_JAVA_OPTIONS -XX:+AlwaysPreTouch -XX:+UseParallelGC -XX:+UseNUMA +ENV maximumPoolSize 300 COPY --from=build $MODULE/build/libs/ROOT.war /usr/local/tomcat/webapps/ROOT.war diff --git a/frameworks/Kotlin/hexagon/hexagon.dockerfile b/frameworks/Kotlin/hexagon/hexagon.dockerfile index 59f89e5cb5c..2654c706db1 100644 --- a/frameworks/Kotlin/hexagon/hexagon.dockerfile +++ b/frameworks/Kotlin/hexagon/hexagon.dockerfile @@ -1,13 +1,13 @@ # # BUILD # -FROM docker.io/gradle:8.9-jdk21-alpine AS build +FROM docker.io/bellsoft/liberica-runtime-container:jdk-all-21-cds-musl AS build USER root WORKDIR /hexagon ADD . . -RUN gradle --quiet classes -RUN gradle --quiet -x test installDist +RUN ./gradlew --quiet classes +RUN ./gradlew --quiet -x test installDist # # RUNTIME @@ -17,6 +17,7 @@ ARG PROJECT=hexagon_jetty_postgresql ENV POSTGRESQL_DB_HOST tfb-database ENV JDK_JAVA_OPTIONS -XX:+AlwaysPreTouch -XX:+UseParallelGC -XX:+UseNUMA +ENV maximumPoolSize 300 COPY --from=build /hexagon/$PROJECT/build/install/$PROJECT /opt/$PROJECT diff --git a/frameworks/Kotlin/hexagon/hexagon_helidon_pgclient/src/main/kotlin/Benchmark.kt b/frameworks/Kotlin/hexagon/hexagon_helidon_pgclient/src/main/kotlin/Benchmark.kt index d38d33281f8..a5778a2c353 100644 --- a/frameworks/Kotlin/hexagon/hexagon_helidon_pgclient/src/main/kotlin/Benchmark.kt +++ b/frameworks/Kotlin/hexagon/hexagon_helidon_pgclient/src/main/kotlin/Benchmark.kt @@ -1,18 +1,30 @@ package com.hexagonkt +import com.hexagonkt.core.Jvm.systemSettingOrNull import com.hexagonkt.core.media.TEXT_HTML import com.hexagonkt.core.urlOf import com.hexagonkt.http.server.helidon.HelidonServerAdapter import com.hexagonkt.store.BenchmarkPgClientStore import com.hexagonkt.templates.jte.JteAdapter +import java.time.Duration fun main() { - val settings = Settings() val store = BenchmarkPgClientStore("postgresql") val templateEngine = JteAdapter(TEXT_HTML, precompiled = true) val templateUrl = urlOf("classpath:fortunes.jte") - val engine = HelidonServerAdapter() + val engine = HelidonServerAdapter( + backlog = systemSettingOrNull("backlog") ?: (8 * 1024), + writeQueueLength = systemSettingOrNull("writeQueueLength") ?: (8 * 1024), + readTimeout = Duration.parse(systemSettingOrNull("readTimeout") ?: "PT0S"), + connectTimeout = Duration.parse(systemSettingOrNull("connectTimeout") ?: "PT0S"), + tcpNoDelay = systemSettingOrNull("tcpNoDelay") ?: true, + receiveLog = systemSettingOrNull("receiveLog") ?: false, + sendLog = systemSettingOrNull("sendLog") ?: false, + validatePath = systemSettingOrNull("validatePath") ?: false, + validateRequestHeaders = systemSettingOrNull("validateRequestHeaders") ?: false, + validateResponseHeaders = systemSettingOrNull("validateResponseHeaders") ?: false, + ) - val benchmark = Benchmark(engine, store, templateEngine, templateUrl, settings) + val benchmark = Benchmark(engine, store, templateEngine, templateUrl, Settings()) benchmark.server.start() } diff --git a/frameworks/Kotlin/hexagon/store_pgclient/src/main/kotlin/BenchmarkPgClientStore.kt b/frameworks/Kotlin/hexagon/store_pgclient/src/main/kotlin/BenchmarkPgClientStore.kt index 1fb9547353f..510abda0295 100644 --- a/frameworks/Kotlin/hexagon/store_pgclient/src/main/kotlin/BenchmarkPgClientStore.kt +++ b/frameworks/Kotlin/hexagon/store_pgclient/src/main/kotlin/BenchmarkPgClientStore.kt @@ -6,8 +6,10 @@ import com.hexagonkt.model.CachedWorld import com.hexagonkt.model.Fortune import com.hexagonkt.model.World import io.vertx.core.Future +import io.vertx.core.Vertx +import io.vertx.core.VertxOptions +import io.vertx.pgclient.PgBuilder import io.vertx.pgclient.PgConnectOptions -import io.vertx.pgclient.PgPool import io.vertx.sqlclient.* import org.cache2k.Cache @@ -35,11 +37,15 @@ class BenchmarkPgClientStore( private val poolOptions: PoolOptions by lazy { PoolOptions().apply { val environment = Jvm.systemSettingOrNull("BENCHMARK_ENV")?.lowercase() - maxSize = 8 + if (environment == "citrine") Jvm.cpuCount else Jvm.cpuCount * 2 + val poolSize = 8 + if (environment == "citrine") Jvm.cpuCount else Jvm.cpuCount * 2 + maxSize = Jvm.systemSettingOrNull(Int::class, "maximumPoolSize") ?: poolSize } } - private val dataSource: SqlClient by lazy { PgPool.client(connectOptions, poolOptions) } + private val dataSource: SqlClient by lazy { + val vertx = Vertx.vertx(VertxOptions().setPreferNativeTransport(true)) + PgBuilder.client().using(vertx).connectingTo(connectOptions).with(poolOptions).build() + } override fun findAllFortunes(): List = dataSource.preparedQuery(SELECT_ALL_FORTUNES) From d8418079a7828386175befd210cbd7af9d6bd183 Mon Sep 17 00:00:00 2001 From: MARiA so cute <33935209+NathanFreeman@users.noreply.github.com> Date: Thu, 19 Sep 2024 22:18:56 +0800 Subject: [PATCH 120/204] fix extension error (#9280) --- frameworks/PHP/swoole/{php.ini => 10-opcache.ini} | 3 +-- frameworks/PHP/swoole/swoole-async-mysql.dockerfile | 8 +++++--- frameworks/PHP/swoole/swoole-async-postgres.dockerfile | 8 +++++--- frameworks/PHP/swoole/swoole-sync-mysql.dockerfile | 8 +++++--- frameworks/PHP/swoole/swoole-sync-postgres.dockerfile | 8 +++++--- 5 files changed, 21 insertions(+), 14 deletions(-) rename frameworks/PHP/swoole/{php.ini => 10-opcache.ini} (89%) diff --git a/frameworks/PHP/swoole/php.ini b/frameworks/PHP/swoole/10-opcache.ini similarity index 89% rename from frameworks/PHP/swoole/php.ini rename to frameworks/PHP/swoole/10-opcache.ini index 089c4837bd5..3e65df6b191 100644 --- a/frameworks/PHP/swoole/php.ini +++ b/frameworks/PHP/swoole/10-opcache.ini @@ -2,9 +2,8 @@ zend_extension=opcache.so opcache.enable=1 opcache.enable_cli=1 opcache.validate_timestamps=0 +opcache.save_comments=0 opcache.enable_file_override=1 opcache.huge_code_pages=1 -memory_limit=1024M - opcache.jit_buffer_size=128M opcache.jit=1225 diff --git a/frameworks/PHP/swoole/swoole-async-mysql.dockerfile b/frameworks/PHP/swoole/swoole-async-mysql.dockerfile index ebfe9084357..b9ce354edb2 100644 --- a/frameworks/PHP/swoole/swoole-async-mysql.dockerfile +++ b/frameworks/PHP/swoole/swoole-async-mysql.dockerfile @@ -18,15 +18,17 @@ RUN apt update -yqq > /dev/null \ && ./configure > /dev/null \ && make -j8 > /dev/null \ && make install > /dev/null \ - && echo "extension=swoole.so" > /etc/php/8.3/cli/conf.d/50-swoole.ini + && echo "extension=swoole.so" > /etc/php/8.3/cli/conf.d/50-swoole.ini \ + && echo "memory_limit=1024M" >> /etc/php/8.3/cli/php.ini \ + && php -m WORKDIR /swoole ADD ./swoole-server.php /swoole -ADD ./php.ini /swoole +ADD 10-opcache.ini /swoole ADD ./database.php /swoole -RUN cat /swoole/php.ini >> /etc/php/8.3/cli/php.ini +COPY 10-opcache.ini /etc/php/8.3/cli/conf.d/10-opcache.ini EXPOSE 8080 CMD php /swoole/swoole-server.php diff --git a/frameworks/PHP/swoole/swoole-async-postgres.dockerfile b/frameworks/PHP/swoole/swoole-async-postgres.dockerfile index f8cd24cc887..3bed20ce226 100644 --- a/frameworks/PHP/swoole/swoole-async-postgres.dockerfile +++ b/frameworks/PHP/swoole/swoole-async-postgres.dockerfile @@ -18,15 +18,17 @@ RUN apt update -yqq > /dev/null \ && ./configure --enable-swoole-pgsql > /dev/null \ && make -j8 > /dev/null \ && make install > /dev/null \ - && echo "extension=swoole.so" > /etc/php/8.3/cli/conf.d/50-swoole.ini + && echo "extension=swoole.so" > /etc/php/8.3/cli/conf.d/50-swoole.ini \ + && echo "memory_limit=1024M" >> /etc/php/8.3/cli/php.ini \ + && php -m WORKDIR /swoole ADD ./swoole-server.php /swoole -ADD ./php.ini /swoole +ADD 10-opcache.ini /swoole ADD ./database.php /swoole -RUN cat /swoole/php.ini >> /etc/php/8.3/cli/php.ini +COPY 10-opcache.ini /etc/php/8.3/cli/conf.d/10-opcache.ini EXPOSE 8080 CMD php /swoole/swoole-server.php diff --git a/frameworks/PHP/swoole/swoole-sync-mysql.dockerfile b/frameworks/PHP/swoole/swoole-sync-mysql.dockerfile index 6c1278bed67..e8de37fd49b 100644 --- a/frameworks/PHP/swoole/swoole-sync-mysql.dockerfile +++ b/frameworks/PHP/swoole/swoole-sync-mysql.dockerfile @@ -18,15 +18,17 @@ RUN apt update -yqq > /dev/null \ && ./configure > /dev/null \ && make -j8 > /dev/null \ && make install > /dev/null \ - && echo "extension=swoole.so" > /etc/php/8.3/cli/conf.d/50-swoole.ini + && echo "extension=swoole.so" > /etc/php/8.3/cli/conf.d/50-swoole.ini \ + && echo "memory_limit=1024M" >> /etc/php/8.3/cli/php.ini \ + && php -m WORKDIR /swoole ADD ./swoole-server.php /swoole -ADD ./php.ini /swoole +ADD 10-opcache.ini /swoole ADD ./database.php /swoole -RUN cat /swoole/php.ini >> /etc/php/8.3/cli/php.ini +COPY 10-opcache.ini /etc/php/8.3/cli/conf.d/10-opcache.ini EXPOSE 8080 CMD php /swoole/swoole-server.php diff --git a/frameworks/PHP/swoole/swoole-sync-postgres.dockerfile b/frameworks/PHP/swoole/swoole-sync-postgres.dockerfile index 8651d205921..670ea96ad4b 100644 --- a/frameworks/PHP/swoole/swoole-sync-postgres.dockerfile +++ b/frameworks/PHP/swoole/swoole-sync-postgres.dockerfile @@ -18,15 +18,17 @@ RUN apt update -yqq > /dev/null \ && ./configure > /dev/null \ && make -j8 > /dev/null \ && make install > /dev/null \ - && echo "extension=swoole.so" > /etc/php/8.3/cli/conf.d/50-swoole.ini + && echo "extension=swoole.so" > /etc/php/8.3/cli/conf.d/50-swoole.ini \ + && echo "memory_limit=1024M" >> /etc/php/8.3/cli/php.ini \ + && php -m WORKDIR /swoole ADD ./swoole-server.php /swoole -ADD ./php.ini /swoole +ADD 10-opcache.ini /swoole ADD ./database.php /swoole -RUN cat /swoole/php.ini >> /etc/php/8.3/cli/php.ini +COPY 10-opcache.ini /etc/php/8.3/cli/conf.d/10-opcache.ini EXPOSE 8080 CMD php /swoole/swoole-server.php From 1f59d8175846a7ef0b114bfcd8ffd5f874a38934 Mon Sep 17 00:00:00 2001 From: Petrik de Heus Date: Thu, 19 Sep 2024 16:19:04 +0200 Subject: [PATCH 121/204] [ruby/hanami] Rename DB namespace for Zeitwerk (#9279) Fixes the following error: Zeitwerk::NameError: expected file /hanami/app/actions/db/index.rb to define constant HelloWorld::Actions::DB::Index, but didn't --- frameworks/Ruby/hanami/app/actions/db/index.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frameworks/Ruby/hanami/app/actions/db/index.rb b/frameworks/Ruby/hanami/app/actions/db/index.rb index 3751a8d0621..c32ec0f1df0 100644 --- a/frameworks/Ruby/hanami/app/actions/db/index.rb +++ b/frameworks/Ruby/hanami/app/actions/db/index.rb @@ -2,7 +2,7 @@ module HelloWorld module Actions - module Db + module DB class Index < HelloWorld::Action QUERY_RANGE = 1..10_000 # range of IDs in the Fortune DB include Deps["persistence.rom"] From 38c2852ad058a55c6231f02d7d76712a1b049d64 Mon Sep 17 00:00:00 2001 From: Petrik de Heus Date: Thu, 19 Sep 2024 16:19:11 +0200 Subject: [PATCH 122/204] [ruby/sinatra-sequel] Upgrade Ruby to 3.4 (#9277) --- .../Ruby/sinatra-sequel/sinatra-sequel-postgres.dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frameworks/Ruby/sinatra-sequel/sinatra-sequel-postgres.dockerfile b/frameworks/Ruby/sinatra-sequel/sinatra-sequel-postgres.dockerfile index 77a2801d16d..eee06752667 100644 --- a/frameworks/Ruby/sinatra-sequel/sinatra-sequel-postgres.dockerfile +++ b/frameworks/Ruby/sinatra-sequel/sinatra-sequel-postgres.dockerfile @@ -1,4 +1,4 @@ -FROM ruby:3.3 +FROM ruby:3.4-rc ENV RUBY_YJIT_ENABLE=1 From 90b1dd3001b5bed98d87beec70217f164936ded8 Mon Sep 17 00:00:00 2001 From: Petrik de Heus Date: Thu, 19 Sep 2024 16:19:18 +0200 Subject: [PATCH 123/204] [ruby/rage] Upgrade Ruby to 3.4 (#9276) --- frameworks/Ruby/rage/Gemfile | 2 +- frameworks/Ruby/rage/rage.dockerfile | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/frameworks/Ruby/rage/Gemfile b/frameworks/Ruby/rage/Gemfile index a7f090d01f9..96d6e7042fc 100644 --- a/frameworks/Ruby/rage/Gemfile +++ b/frameworks/Ruby/rage/Gemfile @@ -3,7 +3,7 @@ source "https://rubygems.org" gem "rage-rb", "~> 1.3" gem "pg", "~> 1.0" -gem "activerecord", "~> 7.0.0", require: "active_record" +gem "activerecord", "~> 7.2.0", require: "active_record" # Build JSON APIs with ease # gem "alba" diff --git a/frameworks/Ruby/rage/rage.dockerfile b/frameworks/Ruby/rage/rage.dockerfile index a1e80a095f3..bbacb344f29 100644 --- a/frameworks/Ruby/rage/rage.dockerfile +++ b/frameworks/Ruby/rage/rage.dockerfile @@ -1,4 +1,4 @@ -FROM ruby:3.3 +FROM ruby:3.4-rc EXPOSE 8080 WORKDIR /rage From 423880cfcecc1c14393cad7d0ccb86fb3c6bcb4f Mon Sep 17 00:00:00 2001 From: Nikolay Kim Date: Thu, 19 Sep 2024 19:19:27 +0500 Subject: [PATCH 124/204] ntex: use released deps (#9269) --- frameworks/Rust/ntex/Cargo.toml | 11 +++-------- frameworks/Rust/ntex/src/db.rs | 27 +++++++++++---------------- 2 files changed, 14 insertions(+), 24 deletions(-) diff --git a/frameworks/Rust/ntex/Cargo.toml b/frameworks/Rust/ntex/Cargo.toml index 850e640f2ad..ec2173e26e3 100755 --- a/frameworks/Rust/ntex/Cargo.toml +++ b/frameworks/Rust/ntex/Cargo.toml @@ -34,10 +34,11 @@ default = [] tokio = ["ntex/tokio"] # compio runtime -compio = ["ntex/compio"] +compio = ["ntex/compio", ] [dependencies] ntex = "2.4" +ntex-compio = "0.1.2" ntex-bytes = { version = "0.1.21", features=["simd"] } mimalloc = { version = "0.1.25", default-features = false } snmalloc-rs = { version = "0.3.3", features = ["native-cpu"] } @@ -52,6 +53,7 @@ futures = "0.3" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" log = { version = "0.4", features = ["release_max_level_off"] } +compio-driver = { version = "0.4", features = ["io-uring", "io-uring-socket"]} tok_io = {version = "1", package = "tokio" } tokio-postgres = { git="https://github.com/fafhrd91/postgres.git", branch="ntex-2" } @@ -63,10 +65,3 @@ lto = "thin" debug = false incremental = false overflow-checks = false - -[patch.crates-io] -ntex = { git = "https://github.com/ntex-rs/ntex.git", branch = "compio" } -ntex-io = { git = "https://github.com/ntex-rs/ntex.git", branch = "compio" } -ntex-rt = { git = "https://github.com/ntex-rs/ntex.git", branch = "compio" } -ntex-net = { git = "https://github.com/ntex-rs/ntex.git", branch = "compio" } -ntex-compio = { git = "https://github.com/ntex-rs/ntex.git", branch = "compio" } diff --git a/frameworks/Rust/ntex/src/db.rs b/frameworks/Rust/ntex/src/db.rs index b3adc6e70bf..c5d525eb6de 100644 --- a/frameworks/Rust/ntex/src/db.rs +++ b/frameworks/Rust/ntex/src/db.rs @@ -68,7 +68,7 @@ impl PgConnection { world, updates, rng: WyRand::new(), - buf: RefCell::new(BytesMut::with_capacity(65535)), + buf: RefCell::new(BytesMut::with_capacity(10 * 1024 * 1024)), } } } @@ -80,7 +80,7 @@ impl PgConnection { let row = self.cl.query_one(&self.world, &[&random_id]).await.unwrap(); let mut body = self.buf.borrow_mut(); - utils::reserve(&mut body, 8 * 1024); + utils::reserve(&mut body, 1024); World { id: row.get(0), randomnumber: row.get(1), @@ -107,7 +107,7 @@ impl PgConnection { } let mut body = self.buf.borrow_mut(); - utils::reserve(&mut body, 8 * 1024); + utils::reserve(&mut body, 2 * 1024); body.put_u8(b'['); worlds.iter().for_each(|w| { w.to_bytes_mut(&mut *body); @@ -119,7 +119,7 @@ impl PgConnection { } pub async fn update(&self, num: usize) -> Bytes { - let mut rng = self.rng.clone(); + let mut rng = nanorand::tls_rng(); let mut queries = SmallVec::<[_; 32]>::new(); (0..num).for_each(|_| { let w_id = (rng.generate::() % 10_000 + 1) as i32; @@ -146,7 +146,7 @@ impl PgConnection { let _ = self.cl.query(&self.updates[num - 1], ¶ms).await; let mut body = self.buf.borrow_mut(); - utils::reserve(&mut body, 8 * 1024); + utils::reserve(&mut body, 2 * 1024); body.put_u8(b'['); worlds.iter().for_each(|w| { w.to_bytes_mut(&mut *body); @@ -158,25 +158,20 @@ impl PgConnection { } pub async fn tell_fortune(&self) -> Bytes { - let fut = self.cl.query_raw(&self.fortune, &[]); + let rows = self.cl.query_raw(&self.fortune, &[]).await.unwrap(); - let rows = fut.await.unwrap(); let mut fortunes: SmallVec<[_; 32]> = smallvec::smallvec![Fortune { id: 0, message: Cow::Borrowed("Additional fortune added at request time."), }]; - - for row in rows { - fortunes.push(Fortune { - id: row.get(0), - message: Cow::Owned(row.get(1)), - }); - } - + fortunes.extend(rows.iter().map(|row| Fortune { + id: row.get(0), + message: Cow::Owned(row.get(1)), + })); fortunes.sort_by(|it, next| it.message.cmp(&next.message)); let mut body = std::mem::replace(&mut *self.buf.borrow_mut(), BytesMut::new()); - utils::reserve(&mut body, 8 * 1024); + utils::reserve(&mut body, 4 * 1024); ywrite_html!(body, "{{> fortune }}"); let result = body.split().freeze(); let _ = std::mem::replace(&mut *self.buf.borrow_mut(), body); From 45c151d5ab020099589d08998318cd0872851131 Mon Sep 17 00:00:00 2001 From: fakeshadow <24548779@qq.com> Date: Thu, 19 Sep 2024 22:21:05 +0800 Subject: [PATCH 125/204] [xitca-web] bug fix and improvements (#9272) * [xitca-web] bug fix and improvements * comment fix --- frameworks/Rust/xitca-web/Cargo.lock | 69 +++++++-------- frameworks/Rust/xitca-web/Cargo.toml | 4 +- frameworks/Rust/xitca-web/src/db.rs | 43 ++++------ frameworks/Rust/xitca-web/src/db_diesel.rs | 49 +++++++---- frameworks/Rust/xitca-web/src/main.rs | 14 +++- frameworks/Rust/xitca-web/src/main_iou.rs | 84 ++----------------- frameworks/Rust/xitca-web/src/ser.rs | 12 +-- frameworks/Rust/xitca-web/src/util.rs | 50 ++++++++--- .../Rust/xitca-web/xitca-web-axum.dockerfile | 2 +- .../Rust/xitca-web/xitca-web-iou.dockerfile | 2 +- .../Rust/xitca-web/xitca-web-sync.dockerfile | 2 +- .../Rust/xitca-web/xitca-web-wasm.dockerfile | 2 +- .../Rust/xitca-web/xitca-web.dockerfile | 2 +- 13 files changed, 145 insertions(+), 190 deletions(-) diff --git a/frameworks/Rust/xitca-web/Cargo.lock b/frameworks/Rust/xitca-web/Cargo.lock index 00bf2423449..14daebadc05 100644 --- a/frameworks/Rust/xitca-web/Cargo.lock +++ b/frameworks/Rust/xitca-web/Cargo.lock @@ -4,18 +4,18 @@ version = 3 [[package]] name = "addr2line" -version = "0.22.0" +version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e4503c46a5c0c7844e948c9a4d6acd9f50cccb4de1c48eb9e291ea17470c678" +checksum = "f5fb1d8e4442bd405fdfd1dacb42792696b0cf9cb15882e5d097b742a676d375" dependencies = [ "gimli", ] [[package]] -name = "adler" -version = "1.0.2" +name = "adler2" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" +checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" [[package]] name = "async-trait" @@ -95,17 +95,17 @@ dependencies = [ [[package]] name = "backtrace" -version = "0.3.73" +version = "0.3.74" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cc23269a4f8976d0a4d2e7109211a419fe30e8d88d677cd60b6bc79c5732e0a" +checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a" dependencies = [ "addr2line", - "cc", "cfg-if", "libc", "miniz_oxide", "object", "rustc-demangle", + "windows-targets", ] [[package]] @@ -149,9 +149,9 @@ checksum = "8318a53db07bb3f8dca91a600466bdb3f2eaadeedfdbcf02e1accbad9271ba50" [[package]] name = "cc" -version = "1.1.16" +version = "1.1.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9d013ecb737093c0e86b151a7b837993cf9ec6c502946cfb44bedc392421e0b" +checksum = "b62ac837cdb5cb22e10a256099b4fc502b1dfe560cb282963a974d7abd80e476" dependencies = [ "shlex", ] @@ -164,9 +164,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "cpufeatures" -version = "0.2.13" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51e852e6dc9a5bed1fae92dd2375037bf2b768725bf3be87811edee3249d09ad" +checksum = "608697df725056feaccfa42cffdaeeec3fccc4ffc38358ecd19b243e716a78e0" dependencies = [ "libc", ] @@ -364,9 +364,9 @@ dependencies = [ [[package]] name = "gimli" -version = "0.29.0" +version = "0.31.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd" +checksum = "32085ea23f3234fc7846555e85283ba4de91e21016dc0455a16286d87a292d64" [[package]] name = "heck" @@ -554,11 +554,11 @@ checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" [[package]] name = "miniz_oxide" -version = "0.7.4" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08" +checksum = "e2d80299ef12ff69b16a84bb182e3b9df68b5a91574d3d4fa6e41b65deec4df1" dependencies = [ - "adler", + "adler2", ] [[package]] @@ -572,12 +572,6 @@ dependencies = [ "windows-sys 0.52.0", ] -[[package]] -name = "nanorand" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a51313c5820b0b02bd422f4b44776fbf47961755c74ce64afc73bfad10226c3" - [[package]] name = "num-traits" version = "0.2.19" @@ -721,9 +715,9 @@ dependencies = [ [[package]] name = "pq-sys" -version = "0.6.1" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a24ff9e4cf6945c988f0db7005d87747bf72864965c3529d259ad155ac41d584" +checksum = "a92c30dd81695321846d4dfe348da67b1752ebb61cd1549d203a7b57e323c435" dependencies = [ "vcpkg", ] @@ -789,9 +783,9 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.5.3" +version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a908a6e00f1fdd0dfd9c0eb08ce85126f6d8bbda50017e74bc4a4b7d4a926a4" +checksum = "0884ad60e090bf1345b93da0a5de8923c93884cd03f40dfcfddd3b4bee661853" dependencies = [ "bitflags 2.6.0", ] @@ -867,18 +861,18 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "serde" -version = "1.0.209" +version = "1.0.210" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99fce0ffe7310761ca6bf9faf5115afbc19688edd00171d81b1bb1b116c63e09" +checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.209" +version = "1.0.210" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5831b979fd7b5439637af1752d535ff49f4860c0f341d1baeb6faf0f4242170" +checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f" dependencies = [ "proc-macro2", "quote", @@ -1155,9 +1149,9 @@ checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" [[package]] name = "unicode-ident" -version = "1.0.12" +version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" +checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" [[package]] name = "unicode-normalization" @@ -1330,9 +1324,9 @@ dependencies = [ [[package]] name = "xitca-io" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "376a4849eef1f3475a6b7a5c474dac278c320a28f6e2abc07be57048b35cc5df" +checksum = "19b91b7a5ff9e3bed167b7e3bcc7b4462d2cb16d05e3ae913dbc384e463fdd7f" dependencies = [ "bytes", "tokio", @@ -1343,7 +1337,7 @@ dependencies = [ [[package]] name = "xitca-postgres" version = "0.1.0" -source = "git+https://github.com/HFQR/xitca-web.git?rev=9835c0b#9835c0b79ebd77f01b74e3ccb1c9893f022db9f3" +source = "git+https://github.com/HFQR/xitca-web.git?rev=0cda225#0cda2254f98b40f21bc3170dd8983f16444f0bd0" dependencies = [ "fallible-iterator", "percent-encoding", @@ -1353,7 +1347,6 @@ dependencies = [ "tokio", "tracing", "xitca-io", - "xitca-service", "xitca-unsafe-collection", ] @@ -1406,7 +1399,7 @@ dependencies = [ "futures-core", "http-body", "mimalloc", - "nanorand", + "rand", "sailfish", "serde", "serde_json", diff --git a/frameworks/Rust/xitca-web/Cargo.toml b/frameworks/Rust/xitca-web/Cargo.toml index 1d6ccc17751..6c16d2d7a54 100644 --- a/frameworks/Rust/xitca-web/Cargo.toml +++ b/frameworks/Rust/xitca-web/Cargo.toml @@ -85,7 +85,7 @@ mimalloc = { version = "0.1", default-features = false, optional = true } # stuff can not be used or not needed in wasi target [target.'cfg(not(target_family = "wasm"))'.dependencies] futures-core = { version = "0.3", default-features = false } -nanorand = { version = "0.7", default-features = false, features = ["tls"] } +rand = { version = "0.8", features = ["small_rng"] } tokio = "1" [profile.release] @@ -95,5 +95,5 @@ codegen-units = 1 panic = "abort" [patch.crates-io] -xitca-postgres = { git = "https://github.com/HFQR/xitca-web.git", rev = "9835c0b" } +xitca-postgres = { git = "https://github.com/HFQR/xitca-web.git", rev = "0cda225" } mio = { git = "https://github.com/fakeshadow/mio", rev = "9bae6012b7ecfc6083350785f71a5e8265358178" } diff --git a/frameworks/Rust/xitca-web/src/db.rs b/frameworks/Rust/xitca-web/src/db.rs index 0b7a18601fb..818804341b1 100644 --- a/frameworks/Rust/xitca-web/src/db.rs +++ b/frameworks/Rust/xitca-web/src/db.rs @@ -1,11 +1,12 @@ -use std::fmt::Write; +// clippy is dumb and have no idea what should be lazy or not +#![allow(clippy::unnecessary_lazy_evaluations)] use xitca_io::bytes::BytesMut; -use xitca_postgres::{pipeline::Pipeline, AsyncLendingIterator, Pool, Type}; +use xitca_postgres::{pipeline::Pipeline, pool::Pool, AsyncLendingIterator, Type}; use super::{ ser::{Fortune, Fortunes, World}, - util::{HandleResult, Rand, DB_URL}, + util::{bulk_update_gen, HandleResult, Rand, DB_URL}, }; pub struct Client { @@ -28,19 +29,14 @@ const WORLD_SQL: &str = "SELECT * FROM world WHERE id=$1"; const WORLD_SQL_TYPES: &[Type] = &[Type::INT4]; fn update_query(num: usize) -> Box { - const PREFIX: &str = "UPDATE world SET randomNumber = w.r FROM (VALUES "; - const SUFFIX: &str = ") AS w (i,r) WHERE world.id = w.i"; - - let (_, mut query) = (1..=num).fold((1, String::from(PREFIX)), |(idx, mut query), _| { - write!(query, "(${}::int,${}::int),", idx, idx + 1).unwrap(); - (idx + 2, query) - }); - - query.pop(); - - query.push_str(SUFFIX); - - query.into_boxed_str() + bulk_update_gen(|query| { + use std::fmt::Write; + (1..=num).fold((1, query), |(idx, query), _| { + write!(query, "(${}::int,${}::int),", idx, idx + 1).unwrap(); + (idx + 2, query) + }); + }) + .into_boxed_str() } pub async fn create() -> HandleResult { @@ -50,14 +46,7 @@ pub async fn create() -> HandleResult { let updates = core::iter::once(Box::from("")) .chain((1..=500).map(update_query)) - .collect::]>>(); - - { - let mut conn = pool.get().await?; - for update in updates.iter().skip(1) { - conn.prepare(update, &[]).await?; - } - } + .collect(); Ok(Client { pool, @@ -120,7 +109,7 @@ impl Client { let mut conn = self.pool.get().await?; let world_stmt = conn.prepare(WORLD_SQL, WORLD_SQL_TYPES).await?; - let update_stmt = conn.prepare(&update, &[]).await?; + let update_stmt = conn.prepare(update, &[]).await?; let mut params = Vec::with_capacity(len); @@ -169,8 +158,8 @@ impl Client { } } -fn sort_update_params(params: &Vec<[i32; 2]>) -> impl ExactSizeIterator { - let mut params = params.clone(); +fn sort_update_params(params: &[[i32; 2]]) -> impl ExactSizeIterator { + let mut params = params.to_owned(); params.sort_by(|a, b| a[0].cmp(&b[0])); struct ParamIter(I); diff --git a/frameworks/Rust/xitca-web/src/db_diesel.rs b/frameworks/Rust/xitca-web/src/db_diesel.rs index 2cd44344499..cf19768ac9f 100644 --- a/frameworks/Rust/xitca-web/src/db_diesel.rs +++ b/frameworks/Rust/xitca-web/src/db_diesel.rs @@ -1,10 +1,13 @@ -use std::sync::{Arc, Mutex}; +use std::{ + io, + sync::{Arc, Mutex}, +}; use diesel::{prelude::*, r2d2}; use crate::{ ser::{Fortune, Fortunes, World}, - util::{Error, HandleResult, Rand, DB_URL}, + util::{bulk_update_gen, Error, HandleResult, Rand, DB_URL}, }; pub type Pool = Arc<_Pool>; @@ -14,7 +17,7 @@ pub struct _Pool { rng: Mutex, } -pub fn create() -> std::io::Result> { +pub fn create() -> io::Result> { r2d2::Builder::new() .max_size(100) .min_idle(Some(100)) @@ -22,7 +25,7 @@ pub fn create() -> std::io::Result> { .idle_timeout(None) .max_lifetime(None) .build(r2d2::ConnectionManager::new(DB_URL)) - .map_err(std::io::Error::other) + .map_err(io::Error::other) .map(|pool| { Arc::new(_Pool { pool, @@ -65,33 +68,32 @@ impl _Pool { pub fn update(&self, num: u16) -> HandleResult> { use crate::schema::world::dsl::*; + let mut rngs = { + let mut rng = self.rng.lock().unwrap(); + (0..num).map(|_| (rng.gen_id(), rng.gen_id())).collect::>() + }; + + rngs.sort_by(|(a, _), (b, _)| a.cmp(b)); + let mut worlds = { let mut conn = self.pool.get()?; - let worlds = (0..num) - .map(|_| { - let mut rng = self.rng.lock().unwrap(); - let w_id = rng.gen_id(); - let r_id = rng.gen_id(); - drop(rng); + + let worlds = rngs + .iter() + .map(|(w_id, num)| { world .filter(id.eq(w_id)) .load::(&mut conn)? .pop() .map(|mut w| { - w.randomnumber = r_id; + w.randomnumber = *num; w }) .ok_or_else(not_found) }) .collect::>>()?; - worlds.iter().try_for_each(|w| { - diesel::update(world) - .filter(id.eq(w.id)) - .set(randomnumber.eq(w.randomnumber)) - .execute(&mut conn) - .map(|_| ()) - })?; + diesel::sql_query(update_query(&rngs)).execute(&mut conn)?; worlds }; @@ -115,3 +117,14 @@ impl _Pool { Ok(Fortunes::new(items)) } } + +// diesel does not support high level bulk update api. use raw sql to bypass the limitation. +// relate discussion: https://github.com/diesel-rs/diesel/discussions/2879 +fn update_query(ids: &[(i32, i32)]) -> String { + bulk_update_gen(|query| { + use std::fmt::Write; + ids.iter().for_each(|(w_id, num)| { + write!(query, "({}::int,{}::int),", w_id, num).unwrap(); + }); + }) +} diff --git a/frameworks/Rust/xitca-web/src/main.rs b/frameworks/Rust/xitca-web/src/main.rs index 06c925bbb25..710ff577586 100755 --- a/frameworks/Rust/xitca-web/src/main.rs +++ b/frameworks/Rust/xitca-web/src/main.rs @@ -39,16 +39,22 @@ async fn middleware(service: &S, req: Ctx<'_>) -> Result Service, Response = Response, Error = RouterError>, { - let mut res = service.call(req).await.unwrap_or_else(|e| match e { + let mut res = service.call(req).await.unwrap_or_else(error_handler); + res.headers_mut().insert(SERVER, SERVER_HEADER_VALUE); + Ok(res) +} + +#[cold] +#[inline(never)] +fn error_handler(e: RouterError) -> Response { + match e { RouterError::Match(_) => error_response(StatusCode::NOT_FOUND), RouterError::NotAllowed(_) => error_response(StatusCode::METHOD_NOT_ALLOWED), RouterError::Service(e) => { println!("{e}"); error_response(StatusCode::INTERNAL_SERVER_ERROR) } - }); - res.headers_mut().insert(SERVER, SERVER_HEADER_VALUE); - Ok(res) + } } async fn plain_text(ctx: Ctx<'_>) -> HandleResult { diff --git a/frameworks/Rust/xitca-web/src/main_iou.rs b/frameworks/Rust/xitca-web/src/main_iou.rs index af6f8424db0..f66eb8778e6 100644 --- a/frameworks/Rust/xitca-web/src/main_iou.rs +++ b/frameworks/Rust/xitca-web/src/main_iou.rs @@ -8,43 +8,31 @@ mod db; mod ser; mod util; -use std::{convert::Infallible, fmt, future::poll_fn, io, pin::pin}; +use std::{convert::Infallible, io}; -use futures_core::stream::Stream; use xitca_http::{ - date::DateTimeService, - h1::proto::context::Context, - http::{header::SERVER, StatusCode}, + body::ResponseBody, + http::{self, header::SERVER, StatusCode}, + HttpServiceBuilder, }; -use xitca_io::{ - bytes::BytesMut, - io_uring::BoundedBuf, - net::{io_uring::TcpStream as IOUTcpStream, TcpStream}, -}; -use xitca_service::{fn_build, fn_service, middleware::UncheckedReady, Service, ServiceExt}; +use xitca_service::{fn_service, ServiceExt}; use self::{ - ser::{error_response, IntoResponse, Message, Request, Response}, + ser::{error_response, IntoResponse, Message, Request}, util::{context_mw, Ctx, QueryParse, SERVER_HEADER_VALUE}, }; fn main() -> io::Result<()> { let service = fn_service(handler) .enclosed(context_mw()) - .enclosed(fn_build(|res: Result<_, _>| async { - res.map(|service| Http1IOU { - service, - date: DateTimeService::new(), - }) - })) - .enclosed(UncheckedReady); + .enclosed(HttpServiceBuilder::h1().io_uring()); xitca_server::Builder::new() .bind("xitca-iou", "0.0.0.0:8080", service)? .build() .wait() } -async fn handler(ctx: Ctx<'_, Request<()>>) -> Result { +async fn handler(ctx: Ctx<'_, Request>) -> Result, Infallible> { let (req, state) = ctx.into_parts(); let mut res = match req.uri().path() { "/plaintext" => req.text_response().unwrap(), @@ -71,59 +59,5 @@ async fn handler(ctx: Ctx<'_, Request<()>>) -> Result { _ => error_response(StatusCode::NOT_FOUND), }; res.headers_mut().insert(SERVER, SERVER_HEADER_VALUE); - Ok(res) -} - -struct Http1IOU { - service: S, - date: DateTimeService, -} - -// runner for http service. -impl Service for Http1IOU -where - S: Service, Response = Response>, - S::Error: fmt::Debug, -{ - type Response = (); - type Error = io::Error; - - async fn call(&self, stream: TcpStream) -> Result { - let std = stream.into_std()?; - let stream = IOUTcpStream::from_std(std); - - let mut ctx = Context::<_, 8>::new(self.date.get()); - let mut read_buf = BytesMut::new(); - let mut write_buf = BytesMut::with_capacity(4096); - - loop { - let len = read_buf.len(); - let rem = read_buf.capacity() - len; - if rem < 4096 { - read_buf.reserve(4096 - rem); - } - - let (res, buf) = stream.read(read_buf.slice(len..)).await; - read_buf = buf.into_inner(); - if res? == 0 { - break; - } - - while let Some((req, _)) = ctx.decode_head::<{ usize::MAX }>(&mut read_buf).unwrap() { - let (parts, body) = self.service.call(req).await.unwrap().into_parts(); - let mut encoder = ctx.encode_head(parts, &body, &mut write_buf).unwrap(); - let mut body = pin!(body); - let chunk = poll_fn(|cx| body.as_mut().poll_next(cx)).await.unwrap().unwrap(); - encoder.encode(chunk, &mut write_buf); - encoder.encode_eof(&mut write_buf); - } - - let (res, b) = stream.write_all(write_buf).await; - write_buf = b; - write_buf.clear(); - res?; - } - - stream.shutdown(std::net::Shutdown::Both) - } + Ok(res.map(Into::into)) } diff --git a/frameworks/Rust/xitca-web/src/ser.rs b/frameworks/Rust/xitca-web/src/ser.rs index e52f2f9c92c..53dcff13cf0 100644 --- a/frameworks/Rust/xitca-web/src/ser.rs +++ b/frameworks/Rust/xitca-web/src/ser.rs @@ -62,7 +62,7 @@ impl Fortune { } } -// TODO: use another template engine with faster compile time.(perferably with no proc macro) +// TODO: use another template engine with faster compile time.(preferably with no proc macro) #[cfg_attr( feature = "template", derive(sailfish::TemplateOnce), @@ -84,11 +84,11 @@ impl<'de> Deserialize<'de> for Num { where D: Deserializer<'de>, { - use core::{cmp, fmt}; + use core::fmt; use serde::de::{Error, MapAccess, Visitor}; - const FIELDS: &'static [&'static str] = &["q"]; + const FIELDS: &[&str] = &["q"]; struct Field; @@ -135,9 +135,7 @@ impl<'de> Deserialize<'de> for Num { V: MapAccess<'de>, { map.next_key::()?.ok_or_else(|| Error::missing_field("q"))?; - let q = map.next_value::().unwrap_or(1); - let q = cmp::min(500, cmp::max(1, q)); - Ok(Num(q)) + Ok(Num(map.next_value().unwrap_or(1).clamp(1, 500))) } } @@ -201,8 +199,6 @@ impl IntoResponse for Request { } } -#[cold] -#[inline(never)] pub fn error_response(status: StatusCode) -> Response { http::Response::builder() .status(status) diff --git a/frameworks/Rust/xitca-web/src/util.rs b/frameworks/Rust/xitca-web/src/util.rs index 707279559ba..62888fb6c26 100755 --- a/frameworks/Rust/xitca-web/src/util.rs +++ b/frameworks/Rust/xitca-web/src/util.rs @@ -1,6 +1,6 @@ #![allow(dead_code)] -use core::{cell::RefCell, cmp}; +use core::cell::RefCell; use xitca_http::{bytes::BytesMut, http::header::HeaderValue}; @@ -10,16 +10,34 @@ pub trait QueryParse { impl QueryParse for Option<&str> { fn parse_query(self) -> u16 { - let num = self - .and_then(|this| { - use atoi::FromRadix10; - this.find('q') - .map(|pos| u16::from_radix_10(this.split_at(pos + 2).1.as_ref()).0) - }) - .unwrap_or(1); + self.and_then(|this| { + use atoi::FromRadix10; + this.find('q') + .map(|pos| u16::from_radix_10(this.split_at(pos + 2).1.as_ref()).0) + }) + .unwrap_or(1) + .clamp(1, 500) + } +} + +pub fn bulk_update_gen(func: F) -> String +where + F: FnOnce(&mut String), +{ + const PREFIX: &str = "UPDATE world SET randomNumber = w.r FROM (VALUES "; + const SUFFIX: &str = ") AS w (i,r) WHERE world.id = w.i"; + + let mut query = String::from(PREFIX); + + func(&mut query); - cmp::min(500, cmp::max(1, num)) + if query.ends_with(',') { + query.pop(); } + + query.push_str(SUFFIX); + + query } #[allow(clippy::declare_interior_mutable_const)] @@ -38,14 +56,20 @@ pub struct State { #[cfg(not(target_arch = "wasm32"))] mod non_wasm { - #[derive(Default)] - pub struct Rand(nanorand::WyRand); + use rand::{rngs::SmallRng, Rng, SeedableRng}; + + pub struct Rand(SmallRng); + + impl Default for Rand { + fn default() -> Self { + Self(SmallRng::from_entropy()) + } + } impl Rand { #[inline] pub fn gen_id(&mut self) -> i32 { - use nanorand::Rng; - (self.0.generate::() % 10_000 + 1) as _ + self.0.gen_range(1..=10000) } } diff --git a/frameworks/Rust/xitca-web/xitca-web-axum.dockerfile b/frameworks/Rust/xitca-web/xitca-web-axum.dockerfile index f5a87ea8ec5..3c6271834ea 100644 --- a/frameworks/Rust/xitca-web/xitca-web-axum.dockerfile +++ b/frameworks/Rust/xitca-web/xitca-web-axum.dockerfile @@ -1,4 +1,4 @@ -FROM rust:1.79 +FROM rust:1.81 ADD ./ /xitca-web WORKDIR /xitca-web diff --git a/frameworks/Rust/xitca-web/xitca-web-iou.dockerfile b/frameworks/Rust/xitca-web/xitca-web-iou.dockerfile index 3b0ef259420..461d5740603 100644 --- a/frameworks/Rust/xitca-web/xitca-web-iou.dockerfile +++ b/frameworks/Rust/xitca-web/xitca-web-iou.dockerfile @@ -1,4 +1,4 @@ -FROM rust:1.79 +FROM rust:1.81 ADD ./ /xitca-web WORKDIR /xitca-web diff --git a/frameworks/Rust/xitca-web/xitca-web-sync.dockerfile b/frameworks/Rust/xitca-web/xitca-web-sync.dockerfile index 21ed93620d3..ad2602a8606 100644 --- a/frameworks/Rust/xitca-web/xitca-web-sync.dockerfile +++ b/frameworks/Rust/xitca-web/xitca-web-sync.dockerfile @@ -1,4 +1,4 @@ -FROM rust:1.79 +FROM rust:1.81 ADD ./ /xitca-web WORKDIR /xitca-web diff --git a/frameworks/Rust/xitca-web/xitca-web-wasm.dockerfile b/frameworks/Rust/xitca-web/xitca-web-wasm.dockerfile index 02634638c16..1c22986b0a2 100644 --- a/frameworks/Rust/xitca-web/xitca-web-wasm.dockerfile +++ b/frameworks/Rust/xitca-web/xitca-web-wasm.dockerfile @@ -1,7 +1,7 @@ ARG WASMTIME_VERSION=15.0.0 ARG WASM_TARGET=wasm32-wasip1-threads -FROM rust:1.79 AS compile +FROM rust:1.81 AS compile ARG WASMTIME_VERSION ARG WASM_TARGET diff --git a/frameworks/Rust/xitca-web/xitca-web.dockerfile b/frameworks/Rust/xitca-web/xitca-web.dockerfile index 0bbd89946c6..d928183362f 100644 --- a/frameworks/Rust/xitca-web/xitca-web.dockerfile +++ b/frameworks/Rust/xitca-web/xitca-web.dockerfile @@ -1,4 +1,4 @@ -FROM rust:1.79 +FROM rust:1.81 ADD ./ /xitca-web WORKDIR /xitca-web From caef9599e77f0693db3db11ce915e2d366af9fa3 Mon Sep 17 00:00:00 2001 From: Yan Kun <1939810907@qq.com> Date: Thu, 19 Sep 2024 22:40:25 +0800 Subject: [PATCH 126/204] [Scala/otavia] upgrade otavia to 0.4.5 (#9275) * [Scala/otavia] upgrade otavia to 0.4.5 * [Scala/otavia] Add a test mutation --- frameworks/Scala/otavia/benchmark_config.json | 48 +------------------ frameworks/Scala/otavia/build.sc | 4 +- frameworks/Scala/otavia/config.toml | 36 +------------- .../otavia-equalization-offgc.dockerfile | 16 ------- .../Scala/otavia/otavia-offgc.dockerfile | 16 ------- ...dockerfile => otavia-overshoot.dockerfile} | 4 +- frameworks/Scala/otavia/otavia.dockerfile | 2 +- 7 files changed, 7 insertions(+), 119 deletions(-) delete mode 100644 frameworks/Scala/otavia/otavia-equalization-offgc.dockerfile delete mode 100644 frameworks/Scala/otavia/otavia-offgc.dockerfile rename frameworks/Scala/otavia/{otavia-equalization.dockerfile => otavia-overshoot.dockerfile} (76%) diff --git a/frameworks/Scala/otavia/benchmark_config.json b/frameworks/Scala/otavia/benchmark_config.json index a93a000f3b4..87204fa771d 100644 --- a/frameworks/Scala/otavia/benchmark_config.json +++ b/frameworks/Scala/otavia/benchmark_config.json @@ -25,53 +25,7 @@ "notes": "", "versus": "Otavia" }, - "equalization": { - "json_url": "/json", - "plaintext_url": "/plaintext", - "db_url": "/db", - "query_url": "/queries?queries=", - "fortune_url": "/fortunes", - "update_url": "/updates?queries=", - "port": 8080, - "approach": "Realistic", - "classification": "Micro", - "database": "Postgres", - "framework": "otavia", - "language": "Scala", - "flavor": "None", - "orm": "Micro", - "platform": "Otavia", - "webserver": "None", - "os": "Linux", - "database_os": "Linux", - "display_name": "otavia", - "notes": "", - "versus": "Otavia" - }, - "equalization-offgc": { - "json_url": "/json", - "plaintext_url": "/plaintext", - "db_url": "/db", - "query_url": "/queries?queries=", - "fortune_url": "/fortunes", - "update_url": "/updates?queries=", - "port": 8080, - "approach": "Realistic", - "classification": "Micro", - "database": "Postgres", - "framework": "otavia", - "language": "Scala", - "flavor": "None", - "orm": "Micro", - "platform": "Otavia", - "webserver": "None", - "os": "Linux", - "database_os": "Linux", - "display_name": "otavia", - "notes": "", - "versus": "Otavia" - }, - "offgc": { + "overshoot": { "json_url": "/json", "plaintext_url": "/plaintext", "db_url": "/db", diff --git a/frameworks/Scala/otavia/build.sc b/frameworks/Scala/otavia/build.sc index 7f872fdf851..c2bf1888dc9 100644 --- a/frameworks/Scala/otavia/build.sc +++ b/frameworks/Scala/otavia/build.sc @@ -1,11 +1,11 @@ import mill._ import mill.scalalib._ -def otaviaVersion = "0.4.3" +def otaviaVersion = "0.4.5" object benchmark extends ScalaModule { - override def scalaVersion = "3.3.1" + override def scalaVersion = "3.3.3" override def ivyDeps = Agg( ivy"cc.otavia::otavia-codec-http:$otaviaVersion", diff --git a/frameworks/Scala/otavia/config.toml b/frameworks/Scala/otavia/config.toml index 9443c4d261b..3a8b7f85e94 100644 --- a/frameworks/Scala/otavia/config.toml +++ b/frameworks/Scala/otavia/config.toml @@ -18,41 +18,7 @@ platform = "Otavia" webserver = "None" versus = "Otavia" -[equalization] -urls.plaintext = "/plaintext" -urls.json = "/json" -urls.db = "/db" -urls.query = "/queries?queries=" -urls.update = "/updates?queries=" -urls.fortune = "/fortunes" -approach = "Realistic" -classification = "Micro" -database = "Postgres" -database_os = "Linux" -os = "Linux" -orm = "Micro" -platform = "Otavia" -webserver = "None" -versus = "Otavia" - -[equalization-offgc] -urls.plaintext = "/plaintext" -urls.json = "/json" -urls.db = "/db" -urls.query = "/queries?queries=" -urls.update = "/updates?queries=" -urls.fortune = "/fortunes" -approach = "Realistic" -classification = "Micro" -database = "Postgres" -database_os = "Linux" -os = "Linux" -orm = "Micro" -platform = "Otavia" -webserver = "None" -versus = "Otavia" - -[offgc] +[overshoot] urls.plaintext = "/plaintext" urls.json = "/json" urls.db = "/db" diff --git a/frameworks/Scala/otavia/otavia-equalization-offgc.dockerfile b/frameworks/Scala/otavia/otavia-equalization-offgc.dockerfile deleted file mode 100644 index 23c9a90fd9e..00000000000 --- a/frameworks/Scala/otavia/otavia-equalization-offgc.dockerfile +++ /dev/null @@ -1,16 +0,0 @@ -FROM nightscape/scala-mill:eclipse-temurin-17.0.8.1_1-jdk-focal_0.11.6_3.3.0 -WORKDIR /otavia -COPY benchmark benchmark -COPY build.sc build.sc -ENV COURSIER_REPOSITORIES=ivy2Local|central -RUN mill benchmark.assembly - -EXPOSE 8080 - -CMD java -server \ - -Dcc.otavia.actor.worker.size=56 -Dcc.otavia.nio.worker.size=56 \ - -Dcc.otavia.system.gc.aggressive=false \ - -jar \ - out/benchmark/assembly.dest/out.jar \ - jdbc:postgresql://tfb-database:5432/hello_world \ - benchmarkdbuser benchmarkdbpass 56 diff --git a/frameworks/Scala/otavia/otavia-offgc.dockerfile b/frameworks/Scala/otavia/otavia-offgc.dockerfile deleted file mode 100644 index 378a48dd2f9..00000000000 --- a/frameworks/Scala/otavia/otavia-offgc.dockerfile +++ /dev/null @@ -1,16 +0,0 @@ -FROM nightscape/scala-mill:eclipse-temurin-17.0.8.1_1-jdk-focal_0.11.6_3.3.0 -WORKDIR /otavia -COPY benchmark benchmark -COPY build.sc build.sc -ENV COURSIER_REPOSITORIES=ivy2Local|central -RUN mill benchmark.assembly - -EXPOSE 8080 - -CMD java -server \ - -Dcc.otavia.actor.worker.size=28 -Dcc.otavia.nio.worker.size=56 \ - -Dcc.otavia.system.gc.aggressive=false \ - -jar \ - out/benchmark/assembly.dest/out.jar \ - jdbc:postgresql://tfb-database:5432/hello_world \ - benchmarkdbuser benchmarkdbpass 56 diff --git a/frameworks/Scala/otavia/otavia-equalization.dockerfile b/frameworks/Scala/otavia/otavia-overshoot.dockerfile similarity index 76% rename from frameworks/Scala/otavia/otavia-equalization.dockerfile rename to frameworks/Scala/otavia/otavia-overshoot.dockerfile index 780aeafe0b0..10df5b40e71 100644 --- a/frameworks/Scala/otavia/otavia-equalization.dockerfile +++ b/frameworks/Scala/otavia/otavia-overshoot.dockerfile @@ -8,8 +8,8 @@ RUN mill benchmark.assembly EXPOSE 8080 CMD java -server \ - -Dcc.otavia.actor.worker.size=56 -Dcc.otavia.nio.worker.size=56 \ + -Dcc.otavia.actor.worker.size=64 \ -jar \ out/benchmark/assembly.dest/out.jar \ jdbc:postgresql://tfb-database:5432/hello_world \ - benchmarkdbuser benchmarkdbpass 56 + benchmarkdbuser benchmarkdbpass 64 diff --git a/frameworks/Scala/otavia/otavia.dockerfile b/frameworks/Scala/otavia/otavia.dockerfile index e407df7ad79..81e16063b03 100644 --- a/frameworks/Scala/otavia/otavia.dockerfile +++ b/frameworks/Scala/otavia/otavia.dockerfile @@ -8,7 +8,7 @@ RUN mill benchmark.assembly EXPOSE 8080 CMD java -server \ - -Dcc.otavia.actor.worker.size=28 -Dcc.otavia.nio.worker.size=56 \ + -Dcc.otavia.actor.worker.size=56 \ -jar \ out/benchmark/assembly.dest/out.jar \ jdbc:postgresql://tfb-database:5432/hello_world \ From 21fde310027d96107da7a771beecb10f6169a429 Mon Sep 17 00:00:00 2001 From: Andrew Stewart Date: Thu, 19 Sep 2024 10:40:36 -0400 Subject: [PATCH 127/204] Disable bandit compression (#9268) --- frameworks/Elixir/phoenix/config/prod.exs | 10 ++++++++-- frameworks/Elixir/phoenix/mix.exs | 2 +- frameworks/Elixir/phoenix/mix.lock | 6 +++--- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/frameworks/Elixir/phoenix/config/prod.exs b/frameworks/Elixir/phoenix/config/prod.exs index 48b24364a40..9ad458a09be 100755 --- a/frameworks/Elixir/phoenix/config/prod.exs +++ b/frameworks/Elixir/phoenix/config/prod.exs @@ -2,8 +2,14 @@ import Config config :hello, HelloWeb.Endpoint, adapter: Bandit.PhoenixAdapter, - http: [port: 8080, ip: {0, 0, 0, 0}], - http_options: [log_protocol_errors: false], + http: [ + port: 8080, + ip: {0, 0, 0, 0}, + http_options: [ + compress: false, + log_protocol_errors: false + ] + ], compress: false, check_origin: false, debug_errors: false, diff --git a/frameworks/Elixir/phoenix/mix.exs b/frameworks/Elixir/phoenix/mix.exs index a0ecab89cd7..c11d586e566 100755 --- a/frameworks/Elixir/phoenix/mix.exs +++ b/frameworks/Elixir/phoenix/mix.exs @@ -29,7 +29,7 @@ defmodule Hello.Mixfile do # Type `mix help deps` for examples and options defp deps do [ - {:bandit, "~> 1.0.0"}, + {:bandit, "1.5.7"}, {:gettext, "~> 0.20"}, {:ecto_sql, "~> 3.10"}, {:jason, "~> 1.2"}, diff --git a/frameworks/Elixir/phoenix/mix.lock b/frameworks/Elixir/phoenix/mix.lock index f3c8c288625..4c59758f12a 100644 --- a/frameworks/Elixir/phoenix/mix.lock +++ b/frameworks/Elixir/phoenix/mix.lock @@ -1,5 +1,5 @@ %{ - "bandit": {:hex, :bandit, "1.0.0", "2bd87bbf713d0eed0090f2fa162cd1676198122e6c2b68a201c706e354a6d5e5", [:mix], [{:hpax, "~> 0.1.1", [hex: :hpax, repo: "hexpm", optional: false]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}, {:thousand_island, "~> 1.0", [hex: :thousand_island, repo: "hexpm", optional: false]}, {:websock, "~> 0.5", [hex: :websock, repo: "hexpm", optional: false]}], "hexpm", "32acf6ac030fee1f99fd9c3fcf81671911ae8637e0a61c98111861b466efafdb"}, + "bandit": {:hex, :bandit, "1.5.7", "6856b1e1df4f2b0cb3df1377eab7891bec2da6a7fd69dc78594ad3e152363a50", [:mix], [{:hpax, "~> 1.0.0", [hex: :hpax, repo: "hexpm", optional: false]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}, {:thousand_island, "~> 1.0", [hex: :thousand_island, repo: "hexpm", optional: false]}, {:websock, "~> 0.5", [hex: :websock, repo: "hexpm", optional: false]}], "hexpm", "f2dd92ae87d2cbea2fa9aa1652db157b6cba6c405cb44d4f6dd87abba41371cd"}, "castore": {:hex, :castore, "1.0.8", "dedcf20ea746694647f883590b82d9e96014057aff1d44d03ec90f36a5c0dc6e", [:mix], [], "hexpm", "0b2b66d2ee742cb1d9cb8c8be3b43c3a70ee8651f37b75a8b982e036752983f1"}, "cowboy": {:hex, :cowboy, "2.12.0", "f276d521a1ff88b2b9b4c54d0e753da6c66dd7be6c9fca3d9418b561828a3731", [:make, :rebar3], [{:cowlib, "2.13.0", [hex: :cowlib, repo: "hexpm", optional: false]}, {:ranch, "1.8.0", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm", "8a7abe6d183372ceb21caa2709bec928ab2b72e18a3911aa1771639bef82651e"}, "cowboy_telemetry": {:hex, :cowboy_telemetry, "0.4.0", "f239f68b588efa7707abce16a84d0d2acf3a0f50571f8bb7f56a15865aae820c", [:rebar3], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "7d98bac1ee4565d31b62d59f8823dfd8356a169e7fcbb83831b8a5397404c9de"}, @@ -10,7 +10,7 @@ "ecto_sql": {:hex, :ecto_sql, "3.11.3", "4eb7348ff8101fbc4e6bbc5a4404a24fecbe73a3372d16569526b0cf34ebc195", [:mix], [{:db_connection, "~> 2.4.1 or ~> 2.5", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.11.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:myxql, "~> 0.6", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.16 or ~> 1.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:tds, "~> 2.1.1 or ~> 2.2", [hex: :tds, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "e5f36e3d736b99c7fee3e631333b8394ade4bafe9d96d35669fca2d81c2be928"}, "expo": {:hex, :expo, "1.0.0", "647639267e088717232f4d4451526e7a9de31a3402af7fcbda09b27e9a10395a", [:mix], [], "hexpm", "18d2093d344d97678e8a331ca0391e85d29816f9664a25653fd7e6166827827c"}, "gettext": {:hex, :gettext, "0.25.0", "98a95a862a94e2d55d24520dd79256a15c87ea75b49673a2e2f206e6ebc42e5d", [:mix], [{:expo, "~> 0.5.1 or ~> 1.0", [hex: :expo, repo: "hexpm", optional: false]}], "hexpm", "38e5d754e66af37980a94fb93bb20dcde1d2361f664b0a19f01e87296634051f"}, - "hpax": {:hex, :hpax, "0.1.2", "09a75600d9d8bbd064cdd741f21fc06fc1f4cf3d0fcc335e5aa19be1a7235c84", [:mix], [], "hexpm", "2c87843d5a23f5f16748ebe77969880e29809580efdaccd615cd3bed628a8c13"}, + "hpax": {:hex, :hpax, "1.0.0", "28dcf54509fe2152a3d040e4e3df5b265dcb6cb532029ecbacf4ce52caea3fd2", [:mix], [], "hexpm", "7f1314731d711e2ca5fdc7fd361296593fc2542570b3105595bb0bc6d0fad601"}, "jason": {:hex, :jason, "1.4.4", "b9226785a9aa77b6857ca22832cffa5d5011a667207eb2a0ad56adb5db443b8a", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "c5eb0cab91f094599f94d55bc63409236a8ec69a21a67814529e8d5f6cc90b3b"}, "mime": {:hex, :mime, "2.0.6", "8f18486773d9b15f95f4f4f1e39b710045fa1de891fada4516559967276e4dc2", [:mix], [], "hexpm", "c9945363a6b26d747389aac3643f8e0e09d30499a138ad64fe8fd1d13d9b153e"}, "nebulex": {:hex, :nebulex, "2.6.3", "78af348ed9f8a338871b41e0b6de718c1808e627ce03fbe86598cbda2bdda2f5", [:mix], [{:decorator, "~> 1.4", [hex: :decorator, repo: "hexpm", optional: true]}, {:shards, "~> 1.1", [hex: :shards, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: true]}], "hexpm", "09cdcbb62f8463ffcec7cae4936425ce91e25d92a6cd37e48b5dda7c851958d5"}, @@ -25,7 +25,7 @@ "plug_crypto": {:hex, :plug_crypto, "2.1.0", "f44309c2b06d249c27c8d3f65cfe08158ade08418cf540fd4f72d4d6863abb7b", [:mix], [], "hexpm", "131216a4b030b8f8ce0f26038bc4421ae60e4bb95c5cf5395e1421437824c4fa"}, "postgrex": {:hex, :postgrex, "0.19.0", "f7d50e50cb42e0a185f5b9a6095125a9ab7e4abccfbe2ab820ab9aa92b71dbab", [:mix], [{:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:table, "~> 0.1.0", [hex: :table, repo: "hexpm", optional: true]}], "hexpm", "dba2d2a0a8637defbf2307e8629cb2526388ba7348f67d04ec77a5d6a72ecfae"}, "ranch": {:hex, :ranch, "1.8.0", "8c7a100a139fd57f17327b6413e4167ac559fbc04ca7448e9be9057311597a1d", [:make, :rebar3], [], "hexpm", "49fbcfd3682fab1f5d109351b61257676da1a2fdbe295904176d5e521a2ddfe5"}, - "telemetry": {:hex, :telemetry, "1.2.1", "68fdfe8d8f05a8428483a97d7aab2f268aaff24b49e0f599faa091f1d4e7f61c", [:rebar3], [], "hexpm", "dad9ce9d8effc621708f99eac538ef1cbe05d6a874dd741de2e689c47feafed5"}, + "telemetry": {:hex, :telemetry, "1.3.0", "fedebbae410d715cf8e7062c96a1ef32ec22e764197f70cda73d82778d61e7a2", [:rebar3], [], "hexpm", "7015fc8919dbe63764f4b4b87a95b7c0996bd539e0d499be6ec9d7f3875b79e6"}, "thousand_island": {:hex, :thousand_island, "1.3.5", "6022b6338f1635b3d32406ff98d68b843ba73b3aa95cfc27154223244f3a6ca5", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "2be6954916fdfe4756af3239fb6b6d75d0b8063b5df03ba76fd8a4c87849e180"}, "websock": {:hex, :websock, "0.5.3", "2f69a6ebe810328555b6fe5c831a851f485e303a7c8ce6c5f675abeb20ebdadc", [:mix], [], "hexpm", "6105453d7fac22c712ad66fab1d45abdf049868f253cf719b625151460b8b453"}, "websock_adapter": {:hex, :websock_adapter, "0.5.6", "0437fe56e093fd4ac422de33bf8fc89f7bc1416a3f2d732d8b2c8fd54792fe60", [:mix], [{:bandit, ">= 0.6.0", [hex: :bandit, repo: "hexpm", optional: true]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.6", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:websock, "~> 0.5", [hex: :websock, repo: "hexpm", optional: false]}], "hexpm", "e04378d26b0af627817ae84c92083b7e97aca3121196679b73c73b99d0d133ea"}, From 15910b2e4245368b288893450664806c252cf09e Mon Sep 17 00:00:00 2001 From: pavelmash <7467039+pavelmash@users.noreply.github.com> Date: Thu, 19 Sep 2024 17:53:44 +0300 Subject: [PATCH 128/204] [mORMot] - mORmot@2.2.8407 + use mormot2 memory manager to found reason of GPF in /plaintext test (#9283) Co-authored-by: pavel.mash --- frameworks/Pascal/mormot/setup_and_build.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frameworks/Pascal/mormot/setup_and_build.sh b/frameworks/Pascal/mormot/setup_and_build.sh index ed0c26034e8..8f2d533127f 100755 --- a/frameworks/Pascal/mormot/setup_and_build.sh +++ b/frameworks/Pascal/mormot/setup_and_build.sh @@ -35,7 +35,7 @@ echo "Download statics from $URL ..." wget -qO- "$URL" | tar -xz -C ./libs/mORMot/static # uncomment for fixed commit URL -URL=https://github.com/synopse/mORMot2/tarball/a0dda41833c3d32531080d1eeb5a1627540d62e9 +URL=https://github.com/synopse/mORMot2/tarball/6dc09ceca456931384857b383ed61b63f11f3be7 #URL="https://api.github.com/repos/synopse/mORMot2/tarball/$USED_TAG" echo "Download and unpacking mORMot sources from $URL ..." wget -qO- "$URL" | tar -xz -C ./libs/mORMot --strip-components=1 @@ -80,7 +80,7 @@ fpc -MDelphi -Sci -Ci -O3 -g -gl -gw2 -Xg -k'-rpath=$ORIGIN' -k-L$BIN \ -Fu"$MSRC/core" -Fu"$MSRC/db" -Fu"$MSRC/rest" -Fu"$MSRC/crypt" \ -Fu"$MSRC/app" -Fu"$MSRC/net" -Fu"$MSRC/lib" -Fu"$MSRC/orm" -Fu"$MSRC/soa" \ -FU"$BIN/fpc-$ARCH_TG/.dcu" -FE"$BIN/fpc-$ARCH_TG" -o"$BIN/fpc-$ARCH_TG/$dest_fn" \ - -dFPC_LIBCMM -dFPC_LIBCMM_NOMSIZE \ + -dFPC_X64MM -dFPCMM_SERVER \ -B -Se1 "./src/raw.pas" | grep "[Warning|Error|Fatal]:" script_successful \ No newline at end of file From 3d85c25d27cddd536b1dc5d4d2b99aec5f54ead4 Mon Sep 17 00:00:00 2001 From: Denis Stepanov Date: Thu, 19 Sep 2024 16:53:52 +0200 Subject: [PATCH 129/204] Micronaut: Use OpenJdk 23 and Graalvm 23 (#9282) * Micronaut: Use Graalvm 23 * Use OpenJdk 23 --- frameworks/Java/micronaut/micronaut-data-jdbc.dockerfile | 2 +- frameworks/Java/micronaut/micronaut-data-mongodb.dockerfile | 2 +- frameworks/Java/micronaut/micronaut-data-r2dbc.dockerfile | 2 +- frameworks/Java/micronaut/micronaut-graalvm.dockerfile | 2 +- frameworks/Java/micronaut/micronaut-jdbc-graalvm.dockerfile | 2 +- frameworks/Java/micronaut/micronaut-jdbc.dockerfile | 2 +- frameworks/Java/micronaut/micronaut-r2dbc-graalvm.dockerfile | 2 +- frameworks/Java/micronaut/micronaut-r2dbc.dockerfile | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) diff --git a/frameworks/Java/micronaut/micronaut-data-jdbc.dockerfile b/frameworks/Java/micronaut/micronaut-data-jdbc.dockerfile index 60c935c6d25..f506d3e9fb8 100644 --- a/frameworks/Java/micronaut/micronaut-data-jdbc.dockerfile +++ b/frameworks/Java/micronaut/micronaut-data-jdbc.dockerfile @@ -3,7 +3,7 @@ COPY --chown=gradle:gradle . /home/gradle/src WORKDIR /home/gradle/src RUN gradle micronaut-data-jdbc:build -x test -x internalStartTestResourcesService --no-daemon -FROM openjdk:21 +FROM openjdk:23 WORKDIR /micronaut COPY --from=build /home/gradle/src/micronaut-data-jdbc/build/libs/micronaut-data-jdbc-all.jar micronaut.jar COPY run_benchmark.sh run_benchmark.sh diff --git a/frameworks/Java/micronaut/micronaut-data-mongodb.dockerfile b/frameworks/Java/micronaut/micronaut-data-mongodb.dockerfile index f098cf335eb..16c0061d17a 100644 --- a/frameworks/Java/micronaut/micronaut-data-mongodb.dockerfile +++ b/frameworks/Java/micronaut/micronaut-data-mongodb.dockerfile @@ -3,7 +3,7 @@ COPY --chown=gradle:gradle . /home/gradle/src WORKDIR /home/gradle/src RUN gradle micronaut-data-mongodb:build -x test -x internalStartTestResourcesService --no-daemon -FROM openjdk:21 +FROM openjdk:23 WORKDIR /micronaut COPY --from=build /home/gradle/src/micronaut-data-mongodb/build/libs/micronaut-data-mongodb-all.jar micronaut.jar COPY run_benchmark.sh run_benchmark.sh diff --git a/frameworks/Java/micronaut/micronaut-data-r2dbc.dockerfile b/frameworks/Java/micronaut/micronaut-data-r2dbc.dockerfile index 0fe88905ef3..f8a07dc83a0 100644 --- a/frameworks/Java/micronaut/micronaut-data-r2dbc.dockerfile +++ b/frameworks/Java/micronaut/micronaut-data-r2dbc.dockerfile @@ -3,7 +3,7 @@ COPY --chown=gradle:gradle . /home/gradle/src WORKDIR /home/gradle/src RUN gradle micronaut-data-r2dbc:build -x test -x internalStartTestResourcesService --no-daemon -FROM openjdk:21 +FROM openjdk:23 WORKDIR /micronaut COPY --from=build /home/gradle/src/micronaut-data-r2dbc/build/libs/micronaut-data-r2dbc-all.jar micronaut.jar COPY run_benchmark.sh run_benchmark.sh diff --git a/frameworks/Java/micronaut/micronaut-graalvm.dockerfile b/frameworks/Java/micronaut/micronaut-graalvm.dockerfile index c1e1207fa96..bbef52f862a 100644 --- a/frameworks/Java/micronaut/micronaut-graalvm.dockerfile +++ b/frameworks/Java/micronaut/micronaut-graalvm.dockerfile @@ -1,4 +1,4 @@ -FROM container-registry.oracle.com/graalvm/native-image:22 +FROM container-registry.oracle.com/graalvm/native-image:23 RUN microdnf install findutils # Gradle 8.7 requires xargs COPY . /home/gradle/src WORKDIR /home/gradle/src diff --git a/frameworks/Java/micronaut/micronaut-jdbc-graalvm.dockerfile b/frameworks/Java/micronaut/micronaut-jdbc-graalvm.dockerfile index 6b6e9262aa2..671d236193d 100644 --- a/frameworks/Java/micronaut/micronaut-jdbc-graalvm.dockerfile +++ b/frameworks/Java/micronaut/micronaut-jdbc-graalvm.dockerfile @@ -1,4 +1,4 @@ -FROM container-registry.oracle.com/graalvm/native-image:22 +FROM container-registry.oracle.com/graalvm/native-image:23 RUN microdnf install findutils # Gradle 8.7 requires xargs COPY . /home/gradle/src WORKDIR /home/gradle/src diff --git a/frameworks/Java/micronaut/micronaut-jdbc.dockerfile b/frameworks/Java/micronaut/micronaut-jdbc.dockerfile index 63b613d4e61..d6a026f0778 100644 --- a/frameworks/Java/micronaut/micronaut-jdbc.dockerfile +++ b/frameworks/Java/micronaut/micronaut-jdbc.dockerfile @@ -3,7 +3,7 @@ COPY --chown=gradle:gradle . /home/gradle/src WORKDIR /home/gradle/src RUN gradle micronaut-jdbc:build -x test -x internalStartTestResourcesService --no-daemon -FROM openjdk:21 +FROM openjdk:23 WORKDIR /micronaut COPY --from=build /home/gradle/src/micronaut-jdbc/build/libs/micronaut-jdbc-all.jar micronaut.jar COPY run_benchmark.sh run_benchmark.sh diff --git a/frameworks/Java/micronaut/micronaut-r2dbc-graalvm.dockerfile b/frameworks/Java/micronaut/micronaut-r2dbc-graalvm.dockerfile index 06ccaea922c..eaf2985de2d 100644 --- a/frameworks/Java/micronaut/micronaut-r2dbc-graalvm.dockerfile +++ b/frameworks/Java/micronaut/micronaut-r2dbc-graalvm.dockerfile @@ -1,4 +1,4 @@ -FROM container-registry.oracle.com/graalvm/native-image:22 +FROM container-registry.oracle.com/graalvm/native-image:23 RUN microdnf install findutils # Gradle 8.7 requires xargs COPY . /home/gradle/src WORKDIR /home/gradle/src diff --git a/frameworks/Java/micronaut/micronaut-r2dbc.dockerfile b/frameworks/Java/micronaut/micronaut-r2dbc.dockerfile index 480b47cffa2..e0fd59fc36b 100644 --- a/frameworks/Java/micronaut/micronaut-r2dbc.dockerfile +++ b/frameworks/Java/micronaut/micronaut-r2dbc.dockerfile @@ -3,7 +3,7 @@ COPY --chown=gradle:gradle . /home/gradle/src WORKDIR /home/gradle/src RUN gradle micronaut-r2dbc:build -x test -x internalStartTestResourcesService --no-daemon -FROM openjdk:21 +FROM openjdk:23 WORKDIR /micronaut COPY --from=build /home/gradle/src/micronaut-r2dbc/build/libs/micronaut-r2dbc-all.jar micronaut.jar COPY run_benchmark.sh run_benchmark.sh From 55a16e9753451e5247b3fd73a49b92b1b508392a Mon Sep 17 00:00:00 2001 From: itrofimow Date: Thu, 19 Sep 2024 22:24:55 +0400 Subject: [PATCH 130/204] [C++] [userver] Remove way too unrealistic "bare" configuration (#9267) * drop bare-configuration from the suite * cleanup README * drop LTO, as userver doesn't support it * remove unrealistic tweaks --- frameworks/C++/userver/README.md | 9 +++--- frameworks/C++/userver/benchmark_config.json | 24 --------------- frameworks/C++/userver/config.toml | 18 ------------ .../C++/userver/userver-bare.dockerfile | 29 ------------------- frameworks/C++/userver/userver.dockerfile | 2 +- .../userver_benchmark/userver_techempower.cpp | 19 ++---------- .../userver_configs/static_config.yaml | 3 -- 7 files changed, 8 insertions(+), 96 deletions(-) delete mode 100644 frameworks/C++/userver/userver-bare.dockerfile diff --git a/frameworks/C++/userver/README.md b/frameworks/C++/userver/README.md index d10de17e403..8b1d83c4d2a 100755 --- a/frameworks/C++/userver/README.md +++ b/frameworks/C++/userver/README.md @@ -2,14 +2,11 @@ This is the [userver](https://github.com/userver-framework/userver) portion of a [benchmarking test suite](https://github.com/TechEmpower/FrameworkBenchmarks) comparing a variety of web development platforms. -This benchmarks comes in two configurations: **userver** and **userver-bare**, where both configurations use exactly the same handlers code, but **userver-bare** replaces default http implementation of **userver** with custom one. -You see, **userver** being feature-rich framework widely used in production comes with a lot of useful functionality built-in (metrics, dynamic configuring, logging/tracing, congestion control etc...) none of which is of any use in benchmarks; although most of that can be disabled via configs, some parts remain, and these parts aren't free. -The aim of **userver-bare** is to explore practical limits of lower-level **userver** functionality when performance is an absolute must, while still being idiomatic userver code. - ### Test Type Implementation Source Code * [Plaintext](userver_benchmark/controllers/plaintext/handler.cpp) * [Json](userver_benchmark/controllers/json/handler.cpp) +* [Fortunes](userver_benchmark/controllers/fortunes/handler.cpp) * [Single Database Query](userver_benchmark/controllers/single_query/handler.cpp) * [Multiple Database Queries](userver_benchmark/controllers/multiple_queries/handler.cpp) * [Database Updates](userver_benchmark/controllers/updates/handler.cpp) @@ -24,6 +21,10 @@ http://localhost:8080/plaintext http://localhost:8080/json +### Fortunes + +http://localhost:8080/fortunes + ### Single Database Query http://localhost:8080/db diff --git a/frameworks/C++/userver/benchmark_config.json b/frameworks/C++/userver/benchmark_config.json index aba5e7d5933..8a455b99a30 100755 --- a/frameworks/C++/userver/benchmark_config.json +++ b/frameworks/C++/userver/benchmark_config.json @@ -25,30 +25,6 @@ "display_name": "userver", "notes": "", "versus": "None" - }, - "bare": { - "json_url": "/json", - "plaintext_url": "/plaintext", - "db_url": "/db", - "query_url": "/queries?queries=", - "update_url": "/updates?queries=", - "cached_query_url": "/cached-queries?count=", - "fortune_url": "/fortunes", - "port": 8081, - "approach": "Realistic", - "classification": "Micro", - "database": "postgres", - "framework": "userver", - "language": "C++", - "flavor": "None", - "orm": "Micro", - "platform": "None", - "webserver": "None", - "os": "Linux", - "database_os": "Linux", - "display_name": "userver[bare]", - "notes": "", - "versus": "None" } } ] diff --git a/frameworks/C++/userver/config.toml b/frameworks/C++/userver/config.toml index 316860f74a1..424fd5d6457 100644 --- a/frameworks/C++/userver/config.toml +++ b/frameworks/C++/userver/config.toml @@ -18,21 +18,3 @@ orm = "Micro" platform = "None" webserver = "None" versus = "None" - -[bare] -urls.plaintext = "/plaintext" -urls.json = "/json" -urls.db = "/db" -urls.query = "/queries?queries=" -urls.update = "/updates?queries=" -urls.cached_query = "/cached-queries?count=" -urls.fortune = "/fortunes" -approach = "Realistic" -classification = "Micro" -database = "Postgres" -database_os = "Linux" -os = "Linux" -orm = "Micro" -platform = "None" -webserver = "None" -versus = "None" diff --git a/frameworks/C++/userver/userver-bare.dockerfile b/frameworks/C++/userver/userver-bare.dockerfile deleted file mode 100644 index 92f8cdaa080..00000000000 --- a/frameworks/C++/userver/userver-bare.dockerfile +++ /dev/null @@ -1,29 +0,0 @@ -FROM ghcr.io/userver-framework/ubuntu-22.04-userver-pg AS builder - -RUN apt update && \ - apt install -y lsb-release wget software-properties-common gnupg && \ - wget https://apt.llvm.org/llvm.sh && chmod +x llvm.sh && ./llvm.sh 16 - -WORKDIR /src -RUN git clone https://github.com/userver-framework/userver.git && \ - cd userver && git checkout bdd5e1e03921ff378b062f86a189c3cfa3d66332 - -COPY userver_benchmark/ ./ -RUN mkdir build && cd build && \ - cmake -DUSERVER_IS_THE_ROOT_PROJECT=0 -DUSERVER_FEATURE_CRYPTOPP_BLAKE2=0 \ - -DUSERVER_FEATURE_UTEST=0 \ - -DUSERVER_FEATURE_POSTGRESQL=1 \ - -DUSERVER_FEATURE_ERASE_LOG_WITH_LEVEL=warning \ - -DCMAKE_BUILD_TYPE=Release -DCMAKE_CXX_FLAGS="-march=native -flto=thin" -DCMAKE_C_FLAGS="-march=native -flto=thin" \ - -DCMAKE_CXX_COMPILER=clang++-16 -DCMAKE_C_COMPILER=clang-16 -DUSERVER_USE_LD=lld-16 \ - -DUSERVER_LTO=0 .. && \ - make -j $(nproc) - -FROM builder AS runner -WORKDIR /app -COPY userver_configs/* ./ -COPY --from=builder /src/build/userver_techempower ./ - -EXPOSE 8081 -CMD ./userver_techempower -c ./static_config.yaml - diff --git a/frameworks/C++/userver/userver.dockerfile b/frameworks/C++/userver/userver.dockerfile index 5f4755e3714..e115816b324 100644 --- a/frameworks/C++/userver/userver.dockerfile +++ b/frameworks/C++/userver/userver.dockerfile @@ -14,7 +14,7 @@ RUN mkdir build && cd build && \ -DUSERVER_FEATURE_UTEST=0 \ -DUSERVER_FEATURE_POSTGRESQL=1 \ -DUSERVER_FEATURE_ERASE_LOG_WITH_LEVEL=warning \ - -DCMAKE_BUILD_TYPE=Release -DCMAKE_CXX_FLAGS="-march=native -flto=thin" -DCMAKE_C_FLAGS="-march=native -flto=thin" \ + -DCMAKE_BUILD_TYPE=Release -DCMAKE_CXX_FLAGS="-march=native" -DCMAKE_C_FLAGS="-march=native" \ -DCMAKE_CXX_COMPILER=clang++-16 -DCMAKE_C_COMPILER=clang-16 -DUSERVER_USE_LD=lld-16 \ -DUSERVER_LTO=0 .. && \ make -j $(nproc) diff --git a/frameworks/C++/userver/userver_benchmark/userver_techempower.cpp b/frameworks/C++/userver/userver_benchmark/userver_techempower.cpp index 6e994d3021c..af0a2b64842 100644 --- a/frameworks/C++/userver/userver_benchmark/userver_techempower.cpp +++ b/frameworks/C++/userver/userver_benchmark/userver_techempower.cpp @@ -46,20 +46,6 @@ class NoopTracingManager final userver::server::http::HttpResponse&) const final {} }; -class MinimalMiddlewarePipelineBuilder final - : public userver::server::middlewares::PipelineBuilder { - public: - static constexpr std::string_view kName{ - "minimal-middleware-pipeline-builder"}; - using userver::server::middlewares::PipelineBuilder::PipelineBuilder; - - private: - userver::server::middlewares::MiddlewaresList BuildPipeline( - userver::server::middlewares::MiddlewaresList) const override { - return {"userver-unknown-exceptions-handling-middleware"}; - } -}; - int Main(int argc, char* argv[]) { auto component_list = userver::components::MinimalServerComponentList() @@ -78,10 +64,9 @@ int Main(int argc, char* argv[]) { .Append() // cache component .Append() .Append() - // tracing and metrics tweaks + // tracing tweaks .Append() - .Append() - // bare + // bare (not used in the benchmark currently) .Append() .Append(); diff --git a/frameworks/C++/userver/userver_configs/static_config.yaml b/frameworks/C++/userver/userver_configs/static_config.yaml index 4d7a7878912..ed793a694a7 100644 --- a/frameworks/C++/userver/userver_configs/static_config.yaml +++ b/frameworks/C++/userver/userver_configs/static_config.yaml @@ -13,7 +13,6 @@ components_manager: thread_name: main-worker # OS will show the threads of this task processor with 'main-worker' prefix. worker_threads: 48 guess-cpu-limit: true - task-processor-queue: work-stealing-task-queue fs-task-processor: # Make a separate task processor for filesystem bound tasks. thread_name: fs-worker @@ -29,7 +28,6 @@ components_manager: handler-defaults: set_tracing_headers: false server-name: us - middleware-pipeline-builder: minimal-middleware-pipeline-builder simple-router: simple-server: port: 8081 @@ -63,7 +61,6 @@ components_manager: noop-tracing-manager: tracing-manager-locator: component-name: noop-tracing-manager - minimal-middleware-pipeline-builder: plaintext-handler: path: /plaintext From 4cbc9751b0a29f813f6092439729624f3bdf0ed1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 20 Sep 2024 14:51:03 +0000 Subject: [PATCH 131/204] Bump puma from 6.4.2 to 6.4.3 in /frameworks/Ruby/rack Bumps [puma](https://github.com/puma/puma) from 6.4.2 to 6.4.3. - [Release notes](https://github.com/puma/puma/releases) - [Changelog](https://github.com/puma/puma/blob/master/History.md) - [Commits](https://github.com/puma/puma/compare/v6.4.2...v6.4.3) --- updated-dependencies: - dependency-name: puma dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- frameworks/Ruby/rack/Gemfile.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frameworks/Ruby/rack/Gemfile.lock b/frameworks/Ruby/rack/Gemfile.lock index f3224c850b1..cf785ab1792 100644 --- a/frameworks/Ruby/rack/Gemfile.lock +++ b/frameworks/Ruby/rack/Gemfile.lock @@ -77,7 +77,7 @@ GEM protocol-rack (0.6.0) protocol-http (~> 0.23) rack (>= 1.0) - puma (6.4.2) + puma (6.4.3) nio4r (~> 2.0) racc (1.8.0) rack (3.1.6) From 5e3690097f7fcfc74e0ccbbbe09ca7c3140e0174 Mon Sep 17 00:00:00 2001 From: Andrew Stewart Date: Mon, 30 Sep 2024 13:53:13 -0400 Subject: [PATCH 132/204] Use transaction for multiple updates, multiple queries (#9263) --- .../hello_web/controllers/page_controller.ex | 63 +++++++++++-------- 1 file changed, 36 insertions(+), 27 deletions(-) diff --git a/frameworks/Elixir/phoenix/lib/hello_web/controllers/page_controller.ex b/frameworks/Elixir/phoenix/lib/hello_web/controllers/page_controller.ex index 34c1fc120fd..7cb7d1fbe2b 100644 --- a/frameworks/Elixir/phoenix/lib/hello_web/controllers/page_controller.ex +++ b/frameworks/Elixir/phoenix/lib/hello_web/controllers/page_controller.ex @@ -1,5 +1,4 @@ defmodule HelloWeb.PageController do - use HelloWeb, :controller alias Hello.Models.Fortune @@ -25,13 +24,18 @@ defmodule HelloWeb.PageController do end def queries(conn, params) do - :rand.seed(:exsp) + {:ok, worlds} = + Repo.transaction(fn -> + :rand.seed(:exsp) - worlds = - Stream.repeatedly(&random_id/0) - |> Stream.uniq() - |> Stream.map(&Repo.get(World, &1)) - |> Enum.take(size(params["queries"])) + worlds = + Stream.repeatedly(&random_id/0) + |> Stream.uniq() + |> Stream.map(&Repo.get(World, &1)) + |> Enum.take(size(params["queries"])) + + worlds + end) json(conn, worlds) end @@ -50,26 +54,31 @@ defmodule HelloWeb.PageController do end def updates(conn, params) do - :rand.seed(:exsp) - - worlds = - Stream.repeatedly(&random_id/0) - |> Stream.uniq() - |> Stream.map(&Repo.get(World, &1)) - |> Stream.map(fn world -> %{id: world.id, randomnumber: :rand.uniform(@random_max)} end) - |> Enum.take(size(params["queries"])) - # If this is not sorted it sometimes generates - # FAIL for http://tfb-server:8080/updates/20 - # Only 20470 executed queries in the database out of roughly 20480 expected. - |> Enum.sort_by(& &1.id) - - Repo.insert_all( - World, - worlds, - on_conflict: {:replace_all_except, [:id]}, - conflict_target: [:id], - returning: false - ) + {:ok, worlds} = + Repo.transaction(fn -> + :rand.seed(:exsp) + + worlds = + Stream.repeatedly(&random_id/0) + |> Stream.uniq() + |> Stream.map(&Repo.get(World, &1)) + |> Stream.map(fn world -> %{id: world.id, randomnumber: :rand.uniform(@random_max)} end) + |> Enum.take(size(params["queries"])) + # If this is not sorted it sometimes generates + # FAIL for http://tfb-server:8080/updates/20 + # Only 20470 executed queries in the database out of roughly 20480 expected. + |> Enum.sort_by(& &1.id) + + Repo.insert_all( + World, + worlds, + on_conflict: {:replace_all_except, [:id]}, + conflict_target: [:id], + returning: false + ) + + worlds + end) json(conn, worlds) end From e816639b2c1c5392baf947109c9e91d35919a736 Mon Sep 17 00:00:00 2001 From: Andy Pan <169128354+andy2pan@users.noreply.github.com> Date: Tue, 1 Oct 2024 01:53:26 +0800 Subject: [PATCH 133/204] gnet: fix a bug of Content-Length header when using wildcat (#9273) --- frameworks/Go/gnet/benchmark_config.json | 4 +- frameworks/Go/gnet/gnet.dockerfile | 2 +- frameworks/Go/gnet/src/go.mod | 20 ++++--- frameworks/Go/gnet/src/go.sum | 47 +++++++--------- frameworks/Go/gnet/src/main.go | 70 +++++++++++++++++++----- 5 files changed, 90 insertions(+), 53 deletions(-) diff --git a/frameworks/Go/gnet/benchmark_config.json b/frameworks/Go/gnet/benchmark_config.json index 3999bd74f97..1ff8439be6d 100644 --- a/frameworks/Go/gnet/benchmark_config.json +++ b/frameworks/Go/gnet/benchmark_config.json @@ -4,8 +4,8 @@ "default": { "plaintext_url": "/plaintext", "port": 8080, - "approach": "stripped", - "classification": "Micro", + "approach": "Realistic", + "classification": "Platform", "database": "None", "framework": "gnet", "language": "Go", diff --git a/frameworks/Go/gnet/gnet.dockerfile b/frameworks/Go/gnet/gnet.dockerfile index 2b060d96acd..bf9715306d8 100644 --- a/frameworks/Go/gnet/gnet.dockerfile +++ b/frameworks/Go/gnet/gnet.dockerfile @@ -1,4 +1,4 @@ -FROM docker.io/golang:1.19 +FROM docker.io/golang:latest WORKDIR /gnet diff --git a/frameworks/Go/gnet/src/go.mod b/frameworks/Go/gnet/src/go.mod index bc59a7c9cfd..77b8811ce55 100644 --- a/frameworks/Go/gnet/src/go.mod +++ b/frameworks/Go/gnet/src/go.mod @@ -1,17 +1,19 @@ module gnet -go 1.19 +go 1.23.1 require ( - github.com/panjf2000/gnet/v2 v2.1.2 - go.uber.org/multierr v1.8.0 // indirect - golang.org/x/sys v0.0.0-20220915200043-7b5979e65e41 // indirect + github.com/evanphx/wildcat v0.0.0-20141114174135-e7012f664567 + github.com/panjf2000/gnet/v2 v2.5.7 ) require ( - github.com/josharian/intern v1.0.0 // indirect - github.com/mailru/easyjson v0.7.7 // indirect - go.uber.org/atomic v1.10.0 // indirect - go.uber.org/zap v1.23.0 // indirect - gopkg.in/natefinch/lumberjack.v2 v2.0.0 // indirect + github.com/valyala/bytebufferpool v1.0.0 // indirect + github.com/vektra/errors v0.0.0-20140903201135-c64d83aba85a // indirect + go.uber.org/atomic v1.7.0 // indirect + go.uber.org/multierr v1.6.0 // indirect + go.uber.org/zap v1.21.0 // indirect + golang.org/x/sync v0.7.0 // indirect + golang.org/x/sys v0.21.0 // indirect + gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect ) diff --git a/frameworks/Go/gnet/src/go.sum b/frameworks/Go/gnet/src/go.sum index f9f9c868493..e39645c8777 100644 --- a/frameworks/Go/gnet/src/go.sum +++ b/frameworks/Go/gnet/src/go.sum @@ -1,46 +1,39 @@ -github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= -github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8= github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= -github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= +github.com/evanphx/wildcat v0.0.0-20141114174135-e7012f664567 h1:7+oQw6YjB/kk9x27AEC7DMXudqERHD583hZpno18lRw= +github.com/evanphx/wildcat v0.0.0-20141114174135-e7012f664567/go.mod h1:XNGflD53X+hfdCAt1NGeBUgiUpe9QmweW/zI1gV26Zw= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= -github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= -github.com/panjf2000/ants/v2 v2.4.8 h1:JgTbolX6K6RreZ4+bfctI0Ifs+3mrE5BIHudQxUDQ9k= -github.com/panjf2000/ants/v2 v2.4.8/go.mod h1:f6F0NZVFsGCp5A7QW/Zj/m92atWwOkY0OIhFxRNFr4A= -github.com/panjf2000/gnet/v2 v2.1.2 h1:WJ/PkbfV6G0wcGOng2pyCwv8oadKiqtP8p+38smN7ao= -github.com/panjf2000/gnet/v2 v2.1.2/go.mod h1:unWr2B4jF0DQPJH3GsXBGQiDcAamM6+Pf5FiK705kc4= +github.com/panjf2000/ants/v2 v2.10.0 h1:zhRg1pQUtkyRiOFo2Sbqwjp0GfBNo9cUY2/Grpx1p+8= +github.com/panjf2000/ants/v2 v2.10.0/go.mod h1:7ZxyxsqE4vvW0M7LSD8aI3cKwgFhBHbxnlN8mDqHa1I= +github.com/panjf2000/gnet/v2 v2.5.7 h1:EGGIfLYEVAp2l5WSYT2XddSjpQ642PjwphbWhcJ0WBY= +github.com/panjf2000/gnet/v2 v2.5.7/go.mod h1:ppopMJ8VrDbJu8kDsqFQTgNmpMS8Le5CmPxISf+Sauk= github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= +github.com/vektra/errors v0.0.0-20140903201135-c64d83aba85a h1:lUVfiMMY/te9icPKBqOKkBIMZNxSpM90dxokDeCcfBg= +github.com/vektra/errors v0.0.0-20140903201135-c64d83aba85a/go.mod h1:KUxJS71XlMs+ztT+RzsLRoWUQRUpECo/+Rb0EBk8/Wc= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= -go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= -go.uber.org/atomic v1.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ= -go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI= go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= +go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4= go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= -go.uber.org/multierr v1.7.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak= -go.uber.org/multierr v1.8.0 h1:dg6GjLku4EH+249NNmoIciG9N/jURbDG+pFlTkhzIC8= -go.uber.org/multierr v1.8.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak= +go.uber.org/zap v1.21.0 h1:WefMeulhovoZ2sYXz7st6K0sLj7bBhpiFaud4r4zST8= go.uber.org/zap v1.21.0/go.mod h1:wjWOCqI0f2ZZrJF/UufIOkiC8ii6tm1iqIsLo76RfJw= -go.uber.org/zap v1.23.0 h1:OjGQ5KQDEUawVHxNwQgPpiypGHOxo2mNZsOqTak4fFY= -go.uber.org/zap v1.23.0/go.mod h1:D+nX8jyLsMHMYrln8A0rJjFt/T/9/bGgIhAqxv5URuY= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= @@ -51,14 +44,15 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= +golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220224120231-95c6836cb0e7/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220915200043-7b5979e65e41 h1:ohgcoMbSofXygzo6AD2I1kz3BFmW1QArPYTtwEM3UXc= -golang.org/x/sys v0.0.0-20220915200043-7b5979e65e41/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws= +golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= @@ -71,12 +65,11 @@ golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/natefinch/lumberjack.v2 v2.0.0 h1:1Lc07Kr7qY4U2YPouBjpCLxpiyxIVoxqXgkXLknAOE8= -gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= -gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc= +gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc= gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/frameworks/Go/gnet/src/main.go b/frameworks/Go/gnet/src/main.go index 88f1fba167c..125e12ac10b 100644 --- a/frameworks/Go/gnet/src/main.go +++ b/frameworks/Go/gnet/src/main.go @@ -7,9 +7,11 @@ import ( "fmt" "log" "runtime" + "strconv" "sync/atomic" "time" + "github.com/evanphx/wildcat" "github.com/panjf2000/gnet/v2" ) @@ -22,30 +24,68 @@ type httpServer struct { } type httpCodec struct { - delimiter []byte - buf []byte + parser *wildcat.HTTPParser + contentLength int + buf []byte } -func (hc *httpCodec) appendResponse() { - hc.buf = append(hc.buf, "HTTP/1.1 200 OK\r\nServer: gnet\r\nContent-Type: text/plain\r\nDate: "...) - //hc.buf = time.Now().AppendFormat(hc.buf, "Mon, 02 Jan 2006 15:04:05 GMT") - hc.buf = append(hc.buf, NowTimeFormat()...) - hc.buf = append(hc.buf, "\r\nContent-Length: 13\r\n\r\nHello, World!"...) -} - -var errCRLFNotFound = errors.New("CRLF not found") +var CRLF = []byte("\r\n\r\n") func (hc *httpCodec) parse(data []byte) (int, error) { - if idx := bytes.Index(data, hc.delimiter); idx != -1 { + // Perform a legit HTTP request parsing. + bodyOffset, err := hc.parser.Parse(data) + if err != nil { + return 0, err + } + + // First check if the Content-Length header is present. + contentLength := hc.getContentLength() + if contentLength > -1 { + return bodyOffset + contentLength, nil + } + + // If the Content-Length header is not found, + // we need to find the end of the body section. + if idx := bytes.Index(data, CRLF); idx != -1 { return idx + 4, nil } - return -1, errCRLFNotFound + + return 0, errors.New("invalid http request") +} + +var contentLengthKey = []byte("Content-Length") + +func (hc *httpCodec) getContentLength() int { + if hc.contentLength != -1 { + return hc.contentLength + } + + val := hc.parser.FindHeader(contentLengthKey) + if val != nil { + i, err := strconv.ParseInt(string(val), 10, 0) + if err == nil { + hc.contentLength = int(i) + } + } + + return hc.contentLength +} + +func (hc *httpCodec) resetParser() { + hc.contentLength = -1 } func (hc *httpCodec) reset() { + hc.resetParser() hc.buf = hc.buf[:0] } +func (hc *httpCodec) appendResponse() { + hc.buf = append(hc.buf, "HTTP/1.1 200 OK\r\nServer: gnet\r\nContent-Type: text/plain\r\nDate: "...) + hc.buf = append(hc.buf, NowTimeFormat()...) + hc.buf = append(hc.buf, "\r\nContent-Length: 13\r\n\r\nHello, World!"...) +} + func (hs *httpServer) OnBoot(eng gnet.Engine) gnet.Action { hs.eng = eng log.Printf("echo server with multi-core=%t is listening on %s\n", hs.multicore, hs.addr) @@ -53,18 +93,20 @@ func (hs *httpServer) OnBoot(eng gnet.Engine) gnet.Action { } func (hs *httpServer) OnOpen(c gnet.Conn) ([]byte, gnet.Action) { - c.SetContext(&httpCodec{delimiter: []byte("\r\n\r\n")}) + c.SetContext(&httpCodec{parser: wildcat.NewHTTPParser()}) return nil, gnet.None } func (hs *httpServer) OnTraffic(c gnet.Conn) gnet.Action { - buf, _ := c.Next(-1) hc := c.Context().(*httpCodec) + buf, _ := c.Next(-1) + pipeline: nextOffset, err := hc.parse(buf) if err != nil { goto response } + hc.resetParser() hc.appendResponse() buf = buf[nextOffset:] if len(buf) > 0 { From c966c96522dcb2fdb4ec73b2b194ab2047bc6463 Mon Sep 17 00:00:00 2001 From: lospejos Date: Mon, 30 Sep 2024 20:53:57 +0300 Subject: [PATCH 134/204] Updated Java version, Maven Docker image, Jooby, Netty versions (#9286) * Bumped version for Java, Jooby, Maven and other libraries/dependencies * Bumped dependencies versions * Bumped dependencies versions * Bumped dependencies versions * Bumped dependencies versions * Fixed Resource_ issue * Bumped versions for Golang, Fiber and other dependencies * Bumped many deps versions, removed deprecated reuseBuffer() in Rocker * Bumped versions for Golang, Fiber and other dependencies * Updated Java version, Maven Docker image, Jooby, Netty versions * Bumped pgx version --- frameworks/Go/fiber/src/go.mod | 4 ++-- frameworks/Go/fiber/src/go.sum | 8 ++++---- frameworks/Java/jooby/jooby-jetty.dockerfile | 2 +- frameworks/Java/jooby/jooby-mvc.dockerfile | 2 +- frameworks/Java/jooby/jooby-netty.dockerfile | 2 +- frameworks/Java/jooby/jooby-pgclient.dockerfile | 2 +- frameworks/Java/jooby/jooby.dockerfile | 2 +- frameworks/Java/jooby/pom.xml | 8 ++++---- 8 files changed, 15 insertions(+), 15 deletions(-) diff --git a/frameworks/Go/fiber/src/go.mod b/frameworks/Go/fiber/src/go.mod index 252db9355e6..36e65622cc4 100644 --- a/frameworks/Go/fiber/src/go.mod +++ b/frameworks/Go/fiber/src/go.mod @@ -5,7 +5,7 @@ go 1.23 require ( github.com/goccy/go-json v0.10.3 github.com/gofiber/fiber/v2 v2.52.5 - github.com/jackc/pgx/v5 v5.6.0 + github.com/jackc/pgx/v5 v5.7.1 github.com/valyala/quicktemplate v1.8.0 ) @@ -14,7 +14,7 @@ require ( github.com/google/uuid v1.6.0 // indirect github.com/jackc/pgpassfile v1.0.0 // indirect github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect - github.com/jackc/puddle/v2 v2.2.1 // indirect + github.com/jackc/puddle/v2 v2.2.2 // indirect github.com/klauspost/compress v1.17.9 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.20 // indirect diff --git a/frameworks/Go/fiber/src/go.sum b/frameworks/Go/fiber/src/go.sum index 1cada1ee655..62741e5425b 100644 --- a/frameworks/Go/fiber/src/go.sum +++ b/frameworks/Go/fiber/src/go.sum @@ -13,10 +13,10 @@ github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsI github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo= github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= -github.com/jackc/pgx/v5 v5.6.0 h1:SWJzexBzPL5jb0GEsrPMLIsi/3jOo7RHlzTjcAeDrPY= -github.com/jackc/pgx/v5 v5.6.0/go.mod h1:DNZ/vlrUnhWCoFGxHAG8U2ljioxukquj7utPDgtQdTw= -github.com/jackc/puddle/v2 v2.2.1 h1:RhxXJtFG022u4ibrCSMSiu5aOq1i77R3OHKNJj77OAk= -github.com/jackc/puddle/v2 v2.2.1/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4= +github.com/jackc/pgx/v5 v5.7.1 h1:x7SYsPBYDkHDksogeSmZZ5xzThcTgRz++I5E+ePFUcs= +github.com/jackc/pgx/v5 v5.7.1/go.mod h1:e7O26IywZZ+naJtWWos6i6fvWK+29etgITqrqHLfoZA= +github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo= +github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4= github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA= github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= diff --git a/frameworks/Java/jooby/jooby-jetty.dockerfile b/frameworks/Java/jooby/jooby-jetty.dockerfile index bd3786886ca..c5d636ada2d 100644 --- a/frameworks/Java/jooby/jooby-jetty.dockerfile +++ b/frameworks/Java/jooby/jooby-jetty.dockerfile @@ -1,4 +1,4 @@ -FROM maven:3.9.6-eclipse-temurin-21-jammy +FROM maven:3.9.9-eclipse-temurin-22-alpine WORKDIR /jooby COPY pom.xml pom.xml COPY src src diff --git a/frameworks/Java/jooby/jooby-mvc.dockerfile b/frameworks/Java/jooby/jooby-mvc.dockerfile index feaeb23bc8e..b2a4db4712b 100644 --- a/frameworks/Java/jooby/jooby-mvc.dockerfile +++ b/frameworks/Java/jooby/jooby-mvc.dockerfile @@ -1,4 +1,4 @@ -FROM maven:3.9.6-eclipse-temurin-21-jammy +FROM maven:3.9.9-eclipse-temurin-22-alpine WORKDIR /jooby COPY pom.xml pom.xml COPY src src diff --git a/frameworks/Java/jooby/jooby-netty.dockerfile b/frameworks/Java/jooby/jooby-netty.dockerfile index dd6afe017c7..1c3efc2585e 100644 --- a/frameworks/Java/jooby/jooby-netty.dockerfile +++ b/frameworks/Java/jooby/jooby-netty.dockerfile @@ -1,4 +1,4 @@ -FROM maven:3.9.6-eclipse-temurin-21-jammy +FROM maven:3.9.9-eclipse-temurin-22-alpine WORKDIR /jooby COPY pom.xml pom.xml COPY src src diff --git a/frameworks/Java/jooby/jooby-pgclient.dockerfile b/frameworks/Java/jooby/jooby-pgclient.dockerfile index e3c58df435c..044cdd5c5de 100644 --- a/frameworks/Java/jooby/jooby-pgclient.dockerfile +++ b/frameworks/Java/jooby/jooby-pgclient.dockerfile @@ -1,4 +1,4 @@ -FROM maven:3.9.6-eclipse-temurin-21-jammy +FROM maven:3.9.9-eclipse-temurin-22-alpine WORKDIR /jooby COPY pom.xml pom.xml COPY src src diff --git a/frameworks/Java/jooby/jooby.dockerfile b/frameworks/Java/jooby/jooby.dockerfile index 98d1b029d36..a5d4570a60d 100644 --- a/frameworks/Java/jooby/jooby.dockerfile +++ b/frameworks/Java/jooby/jooby.dockerfile @@ -1,4 +1,4 @@ -FROM maven:3.9.6-eclipse-temurin-21-jammy +FROM maven:3.9.9-eclipse-temurin-22-alpine WORKDIR /jooby COPY pom.xml pom.xml COPY src src diff --git a/frameworks/Java/jooby/pom.xml b/frameworks/Java/jooby/pom.xml index 99170fb8cfe..3b6edfc79ec 100644 --- a/frameworks/Java/jooby/pom.xml +++ b/frameworks/Java/jooby/pom.xml @@ -11,13 +11,13 @@ jooby - 3.2.9 - 4.1.112.Final + 3.4.0 + 4.1.113.Final 2.0.2 42.7.4 UTF-8 - 21 - 21 + 22 + 22 com.techempower.App From d4b3ac80417a0328f2d1649d721d9120770078c7 Mon Sep 17 00:00:00 2001 From: LLT21 <43903768+LLT21@users.noreply.github.com> Date: Mon, 30 Sep 2024 19:54:17 +0200 Subject: [PATCH 135/204] Use asynchronous data access methods in appMpower.Orm (#9281) * Use asynchronous data access methods in appMpower.Orm * Improved connection pool handling * Using tuple with base connection elements instead of "this" for pooling * Improved caching * Better separation of keyed and unkeyed command caching --------- Co-authored-by: LLT21 <> --- .../src/appMpower.Orm/Data/DbCommand.cs | 16 ++-- .../src/appMpower.Orm/Data/DbConnection.cs | 87 ++++++++++++------- .../src/appMpower.Orm/Data/DbConnections.cs | 64 +++++++------- .../appMpower.Orm/Data/DbConnectionsKeyed.cs | 61 +++++++++++++ .../src/appMpower.Orm/DotnetMethods.cs | 8 +- .../src/appMpower.Orm/NativeMethods.cs | 10 +-- .../appmpower/src/appMpower.Orm/RawDb.cs | 65 +++++++------- 7 files changed, 192 insertions(+), 119 deletions(-) create mode 100644 frameworks/CSharp/appmpower/src/appMpower.Orm/Data/DbConnectionsKeyed.cs diff --git a/frameworks/CSharp/appmpower/src/appMpower.Orm/Data/DbCommand.cs b/frameworks/CSharp/appmpower/src/appMpower.Orm/Data/DbCommand.cs index a580aa5e110..0dfe4581906 100644 --- a/frameworks/CSharp/appmpower/src/appMpower.Orm/Data/DbCommand.cs +++ b/frameworks/CSharp/appmpower/src/appMpower.Orm/Data/DbCommand.cs @@ -20,12 +20,6 @@ public DbCommand(string commandText, DbConnection dbConnection) _dbConnection = dbConnection; } - public DbCommand(string commandText, DbConnection dbConnection, bool keyed) - { - _odbcCommand = dbConnection.GetCommand(commandText, CommandType.Text, keyed); - _dbConnection = dbConnection; - } - public DbCommand(string commandText, CommandType commandType, DbConnection dbConnection) { _odbcCommand = dbConnection.GetCommand(commandText, commandType); @@ -175,7 +169,7 @@ public IDataReader ExecuteReader() public async Task ExecuteNonQueryAsync() { - return await (_odbcCommand as System.Data.Common.DbCommand).ExecuteNonQueryAsync(); + return await _odbcCommand.ExecuteNonQueryAsync(); } public IDataReader ExecuteReader(CommandBehavior behavior) @@ -183,6 +177,11 @@ public IDataReader ExecuteReader(CommandBehavior behavior) return _odbcCommand.ExecuteReader(behavior); } + public async Task ExecuteReaderAsync(CommandBehavior behavior) + { + return await _odbcCommand.ExecuteReaderAsync(behavior); + } + #nullable enable public object? ExecuteScalar() { @@ -197,8 +196,7 @@ public void Prepare() public void Dispose() { - if (_dbConnection._keyed) _dbConnection._keyedOdbcCommands.TryAdd(_odbcCommand.CommandText, _odbcCommand); - else _dbConnection._odbcCommands.Push(_odbcCommand); + _dbConnection.Release(_odbcCommand); } } } \ No newline at end of file diff --git a/frameworks/CSharp/appmpower/src/appMpower.Orm/Data/DbConnection.cs b/frameworks/CSharp/appmpower/src/appMpower.Orm/Data/DbConnection.cs index ba3b6cf85b6..1a9c5ae0355 100644 --- a/frameworks/CSharp/appmpower/src/appMpower.Orm/Data/DbConnection.cs +++ b/frameworks/CSharp/appmpower/src/appMpower.Orm/Data/DbConnection.cs @@ -1,26 +1,27 @@ using System.Collections.Concurrent; using System.Data; -using System.Data.Odbc; +using System.Data.Odbc; namespace appMpower.Orm.Data { public class DbConnection : IDbConnection { private string _connectionString; - internal bool _keyed = false; - internal int _number; - internal OdbcConnection _odbcConnection; - internal ConcurrentStack _odbcCommands = new(); - internal Dictionary _keyedOdbcCommands; + private bool _keyed = false; + private int _number; + private OdbcConnection _odbcConnection; + private ConcurrentStack _odbcCommands = new(); + private Dictionary _keyedOdbcCommands; public DbConnection() { - _connectionString = DbProviderFactory.ConnectionString; } - public DbConnection(string connectionString) + public DbConnection(string connectionString, bool keyed = false) { - _connectionString = connectionString; + _keyed = keyed; + _connectionString = connectionString; + GetConnection(); } public IDbConnection Connection @@ -43,7 +44,22 @@ public string ConnectionString } set { - _odbcConnection.ConnectionString = value; + _connectionString = value; + GetConnection(); + } + } + + private void GetConnection() + { + if (_keyed) + { + (_number, _odbcConnection, _keyedOdbcCommands) = + DbConnectionsKeyed.GetConnectionBase(_connectionString).GetAwaiter().GetResult(); + } + else + { + (_number, _odbcConnection, _odbcCommands) = + DbConnections.GetConnectionBase(_connectionString).GetAwaiter().GetResult(); } } @@ -99,23 +115,33 @@ public IDbCommand CreateCommand() public void Open() { - if (_odbcConnection is null) + if (_odbcConnection.State == ConnectionState.Closed) { - DbConnections.GetConnection(_connectionString, this); + _odbcConnection.Open(); } + } + public async Task OpenAsync() + { if (_odbcConnection.State == ConnectionState.Closed) { - _odbcConnection.Open(); + await _odbcConnection.OpenAsync(); } } public void Dispose() { - DbConnections.Release(this); + if (_keyed) + { + DbConnectionsKeyed.Release((Number: _number, OdbcConnection: _odbcConnection, KeyedOdbcCommands: _keyedOdbcCommands)); + } + else + { + DbConnections.Release((Number: _number, OdbcConnection: _odbcConnection, OdbcCommands: _odbcCommands)); + } } - internal OdbcCommand GetCommand(string commandText, CommandType commandType, bool keyed = false) + internal OdbcCommand GetCommand(string commandText, CommandType commandType) { OdbcCommand odbcCommand; @@ -129,25 +155,20 @@ internal OdbcCommand GetCommand(string commandText, CommandType commandType, boo return odbcCommand; } - else if (_keyed && _keyedOdbcCommands.TryGetValue(commandText, out odbcCommand)) - { - return odbcCommand; - } - else - { - if (!_keyed && keyed) - { - _keyedOdbcCommands = new(); - _keyed = keyed; - } - - odbcCommand = _odbcConnection.CreateCommand(); - odbcCommand.CommandText = commandText; - odbcCommand.CommandType = commandType; - odbcCommand.Prepare(); + else if (_keyed && _keyedOdbcCommands.TryGetValue(commandText, out odbcCommand)) return odbcCommand; - return odbcCommand; - } + odbcCommand = _odbcConnection.CreateCommand(); + odbcCommand.CommandText = commandText; + odbcCommand.CommandType = commandType; + odbcCommand.Prepare(); + + return odbcCommand; + } + + internal void Release(OdbcCommand odbcCommand) + { + if (_keyed) _keyedOdbcCommands.TryAdd(odbcCommand.CommandText, odbcCommand); + else _odbcCommands.Push(odbcCommand); } } } \ No newline at end of file diff --git a/frameworks/CSharp/appmpower/src/appMpower.Orm/Data/DbConnections.cs b/frameworks/CSharp/appmpower/src/appMpower.Orm/Data/DbConnections.cs index 514e2945d38..b278e54fa57 100644 --- a/frameworks/CSharp/appmpower/src/appMpower.Orm/Data/DbConnections.cs +++ b/frameworks/CSharp/appmpower/src/appMpower.Orm/Data/DbConnections.cs @@ -1,61 +1,61 @@ using System.Collections.Concurrent; +using System.Data.Odbc; namespace appMpower.Orm.Data { - public static class DbConnections + internal static class DbConnections { + private static bool _maxConnectionsCreated = false; private static short _createdConnections = 0; - private static ConcurrentStack _connectionsStack = new(); + private static short _maxConnections = 500; - public static DbConnection GetConnection(string connectionString) + private static ConcurrentStack<(int Number, OdbcConnection OdbcConnection, ConcurrentStack OdbcCommands)> _connectionsStack = new(); + private static ConcurrentQueue OdbcCommands)>> _waitingQueue = new(); + + internal static async Task<(int Number, OdbcConnection OdbcConnection, ConcurrentStack OdbcCommands)> GetConnectionBase(string connectionString) { - DbConnection popDbConnection; + (int Number, OdbcConnection OdbcConnection, ConcurrentStack OdbcCommands) dbConnectionBase; - if (!_connectionsStack.TryPop(out popDbConnection)) + if (!_connectionsStack.TryPop(out dbConnectionBase)) { - popDbConnection = new DbConnection(); - popDbConnection._odbcConnection = new System.Data.Odbc.OdbcConnection(connectionString); + if (_maxConnectionsCreated) + { + dbConnectionBase = await GetDbConnectionBaseAsync(); + } + else + { + _createdConnections++; + dbConnectionBase = (Number: _maxConnections, OdbcConnection: new OdbcConnection(connectionString), OdbcCommands: new ConcurrentStack()); - _createdConnections++; - popDbConnection._number = _createdConnections; + if (_createdConnections == _maxConnections) _maxConnectionsCreated = true; - if (_createdConnections % 25 == 0) - { - Console.WriteLine("Pooled connections created: " + _createdConnections.ToString()); + //Console.WriteLine("opened connection number: " + dbConnectionBase._number); } } - return popDbConnection; + return dbConnectionBase; } - - public static void GetConnection(string connectionString, DbConnection dbConnection) + internal static void Release((int Number, OdbcConnection OdbcConnection, ConcurrentStack OdbcCommands) dbConnectionBase) { - DbConnection popDbConnection = null; + TaskCompletionSource<(int Number, OdbcConnection OdbcConnection, ConcurrentStack OdbcCommands)> taskCompletionSource; - if (_connectionsStack.TryPop(out popDbConnection)) + if (_waitingQueue.TryDequeue(out taskCompletionSource)) { - dbConnection._odbcConnection = popDbConnection._odbcConnection; - dbConnection._odbcCommands = popDbConnection._odbcCommands; - dbConnection._number = popDbConnection._number; + taskCompletionSource.SetResult(dbConnectionBase); } else { - dbConnection._odbcConnection = new System.Data.Odbc.OdbcConnection(connectionString); - - _createdConnections++; - dbConnection._number = _createdConnections; - - if (_createdConnections % 25 == 0) - { - Console.WriteLine("Pooled connections created: " + _createdConnections.ToString()); - } - } + _connectionsStack.Push(dbConnectionBase); + } } - public static void Release(DbConnection dbConnection) + private static Task<(int Number, OdbcConnection OdbcConnection, ConcurrentStack OdbcCommands)> GetDbConnectionBaseAsync() { - _connectionsStack.Push(dbConnection); + var taskCompletionSource = new TaskCompletionSource<(int Number, OdbcConnection OdbcConnection, ConcurrentStack OdbcCommands)>(TaskCreationOptions.RunContinuationsAsynchronously); + + _waitingQueue.Enqueue(taskCompletionSource); + return taskCompletionSource.Task; } } } \ No newline at end of file diff --git a/frameworks/CSharp/appmpower/src/appMpower.Orm/Data/DbConnectionsKeyed.cs b/frameworks/CSharp/appmpower/src/appMpower.Orm/Data/DbConnectionsKeyed.cs new file mode 100644 index 00000000000..25cd4dcbab7 --- /dev/null +++ b/frameworks/CSharp/appmpower/src/appMpower.Orm/Data/DbConnectionsKeyed.cs @@ -0,0 +1,61 @@ +using System.Collections.Concurrent; +using System.Data.Odbc; + +namespace appMpower.Orm.Data +{ + internal static class DbConnectionsKeyed + { + private static bool _maxConnectionsCreated = false; + private static short _createdConnections = 0; + private static short _maxConnections = 500; + + private static ConcurrentStack<(int Number, OdbcConnection OdbcConnection, Dictionary)> _connectionsStack = new(); + private static ConcurrentQueue)>> _waitingQueue = new(); + + internal static async Task<(int Number, OdbcConnection OdbcConnection, Dictionary KeyedOdbcCommands)> GetConnectionBase(string connectionString) + { + (int Number, OdbcConnection OdbcConnection, Dictionary KeyedOdbcCommands) dbConnectionBase; + + if (!_connectionsStack.TryPop(out dbConnectionBase)) + { + if (_maxConnectionsCreated) + { + dbConnectionBase = await GetDbConnectionBaseAsync(); + } + else + { + _createdConnections++; + dbConnectionBase = (Number: _maxConnections, OdbcConnection: new OdbcConnection(connectionString), KeyedOdbcCommands: new Dictionary()); + + if (_createdConnections == _maxConnections) _maxConnectionsCreated = true; + + //Console.WriteLine("opened connection number: " + dbConnectionBase._number); + } + } + + return dbConnectionBase; + } + + internal static void Release((int Number, OdbcConnection OdbcConnection, Dictionary KeyedOdbcCommands) dbConnectionBase) + { + TaskCompletionSource<(int Number, OdbcConnection OdbcConnection, Dictionary)> taskCompletionSource; + + if (_waitingQueue.TryDequeue(out taskCompletionSource)) + { + taskCompletionSource.SetResult(dbConnectionBase); + } + else + { + _connectionsStack.Push(dbConnectionBase); + } + } + + private static Task<(int Number, OdbcConnection OdbcConnection, Dictionary)> GetDbConnectionBaseAsync() + { + var taskCompletionSource = new TaskCompletionSource<(int Number, OdbcConnection OdbcConnection, Dictionary)>(TaskCreationOptions.RunContinuationsAsynchronously); + + _waitingQueue.Enqueue(taskCompletionSource); + return taskCompletionSource.Task; + } + } +} \ No newline at end of file diff --git a/frameworks/CSharp/appmpower/src/appMpower.Orm/DotnetMethods.cs b/frameworks/CSharp/appmpower/src/appMpower.Orm/DotnetMethods.cs index f6b8b4cad1c..5ea4ce43fa2 100644 --- a/frameworks/CSharp/appmpower/src/appMpower.Orm/DotnetMethods.cs +++ b/frameworks/CSharp/appmpower/src/appMpower.Orm/DotnetMethods.cs @@ -21,7 +21,7 @@ public static class DotnetMethods public static byte[] Db() { - var world = RawDb.LoadSingleQueryRow(); + var world = RawDb.LoadSingleQueryRow().GetAwaiter().GetResult(); var memoryStream = new MemoryStream(); using var utf8JsonWriter = new Utf8JsonWriter(memoryStream, _jsonWriterOptions); @@ -33,7 +33,7 @@ public static byte[] Db() public static byte[] Query(int queries) { - World[] worlds = RawDb.ReadMultipleRows(queries); + World[] worlds = RawDb.ReadMultipleRows(queries).GetAwaiter().GetResult(); var memoryStream = new MemoryStream(); using var utf8JsonWriter = new Utf8JsonWriter(memoryStream, _jsonWriterOptions); @@ -45,7 +45,7 @@ public static byte[] Query(int queries) public static byte[] Updates(int count) { - World[] worlds = RawDb.LoadMultipleUpdatesRows(count); + World[] worlds = RawDb.LoadMultipleUpdatesRows(count).GetAwaiter().GetResult(); var memoryStream = new MemoryStream(); using var utf8JsonWriter = new Utf8JsonWriter(memoryStream, _jsonWriterOptions); @@ -57,7 +57,7 @@ public static byte[] Updates(int count) public static byte[] Fortunes() { - List fortunes = RawDb.LoadFortunesRows(); + List fortunes = RawDb.LoadFortunesRows().GetAwaiter().GetResult(); string fortunesView = FortunesView.Render(fortunes); byte[] byteArray = Encoding.UTF8.GetBytes(fortunesView); diff --git a/frameworks/CSharp/appmpower/src/appMpower.Orm/NativeMethods.cs b/frameworks/CSharp/appmpower/src/appMpower.Orm/NativeMethods.cs index 0f3ee5b59c2..64337e6269e 100644 --- a/frameworks/CSharp/appmpower/src/appMpower.Orm/NativeMethods.cs +++ b/frameworks/CSharp/appmpower/src/appMpower.Orm/NativeMethods.cs @@ -42,7 +42,7 @@ public static void FreeHandlePointer(IntPtr handlePointer) [UnmanagedCallersOnly(EntryPoint = "Db")] public static unsafe IntPtr Db(int* length, IntPtr* handlePointer) { - var world = RawDb.LoadSingleQueryRow(); + var world = RawDb.LoadSingleQueryRow().GetAwaiter().GetResult(); var memoryStream = new MemoryStream(); using var utf8JsonWriter = new Utf8JsonWriter(memoryStream, _jsonWriterOptions); @@ -69,7 +69,7 @@ public static unsafe IntPtr Db(int* length, IntPtr* handlePointer) [UnmanagedCallersOnly(EntryPoint = "Fortunes")] public static unsafe IntPtr Fortunes(int* length, IntPtr* handlePointer) { - List fortunes = RawDb.LoadFortunesRows(); + List fortunes = RawDb.LoadFortunesRows().GetAwaiter().GetResult(); string fortunesView = FortunesView.Render(fortunes); byte[] byteArray = Encoding.UTF8.GetBytes(fortunesView); @@ -85,7 +85,7 @@ public static unsafe IntPtr Fortunes(int* length, IntPtr* handlePointer) [UnmanagedCallersOnly(EntryPoint = "Query")] public static unsafe IntPtr Query(int queries, int* length, IntPtr* handlePointer) { - World[] worlds = RawDb.ReadMultipleRows(queries); + World[] worlds = RawDb.ReadMultipleRows(queries).GetAwaiter().GetResult(); var memoryStream = new MemoryStream(); using var utf8JsonWriter = new Utf8JsonWriter(memoryStream, _jsonWriterOptions); @@ -105,7 +105,7 @@ public static unsafe IntPtr Query(int queries, int* length, IntPtr* handlePointe [UnmanagedCallersOnly(EntryPoint = "Updates")] public static unsafe IntPtr Updates(int count, int* length, IntPtr* handlePointer) { - World[] worlds = RawDb.LoadMultipleUpdatesRows(count); + World[] worlds = RawDb.LoadMultipleUpdatesRows(count).GetAwaiter().GetResult(); var memoryStream = new MemoryStream(); using var utf8JsonWriter = new Utf8JsonWriter(memoryStream, _jsonWriterOptions); @@ -125,7 +125,7 @@ public static unsafe IntPtr Updates(int count, int* length, IntPtr* handlePointe [UnmanagedCallersOnly(EntryPoint = "DbById")] public static unsafe IntPtr DbById(int id, int* length, IntPtr* handlePointer) { - var world = RawDb.LoadSingleQueryRowById(id); + var world = RawDb.LoadSingleQueryRowById(id).GetAwaiter().GetResult(); var memoryStream = new MemoryStream(); using var utf8JsonWriter = new Utf8JsonWriter(memoryStream, _jsonWriterOptions); diff --git a/frameworks/CSharp/appmpower/src/appMpower.Orm/RawDb.cs b/frameworks/CSharp/appmpower/src/appMpower.Orm/RawDb.cs index b748d78a251..fec986f8755 100644 --- a/frameworks/CSharp/appmpower/src/appMpower.Orm/RawDb.cs +++ b/frameworks/CSharp/appmpower/src/appMpower.Orm/RawDb.cs @@ -13,42 +13,42 @@ public static class RawDb private static string[] _queriesMultipleRows = new string[MaxBatch + 1]; - public static World LoadSingleQueryRow() + public static async Task LoadSingleQueryRow() { - using var pooledConnection = DbConnections.GetConnection(DbProviderFactory.ConnectionString); - pooledConnection.Open(); + using var pooledConnection = new DbConnection(DbProviderFactory.ConnectionString); + await pooledConnection.OpenAsync(); var (dbCommand, _) = CreateReadCommand(pooledConnection); using (dbCommand) { - World world = ReadSingleRow(dbCommand); + World world = await ReadSingleRow(dbCommand); return world; } } - public static World LoadSingleQueryRowById(int id) + public static async Task LoadSingleQueryRowById(int id) { - using var pooledConnection = DbConnections.GetConnection(DbProviderFactory.ConnectionString); - pooledConnection.Open(); + using var pooledConnection = new DbConnection(DbProviderFactory.ConnectionString); + await pooledConnection.OpenAsync(); var (dbCommand, _) = CreateReadCommandById(pooledConnection, id); using (dbCommand) { - World world = ReadSingleRow(dbCommand); + World world = await ReadSingleRow(dbCommand); return world; } } - public static World[] LoadMultipleQueriesRows(int count) + public static async Task LoadMultipleQueriesRows(int count) { var worlds = new World[count]; - using var pooledConnection = DbConnections.GetConnection(DbProviderFactory.ConnectionString); - pooledConnection.Open(); + using var pooledConnection = new DbConnection(DbProviderFactory.ConnectionString); + await pooledConnection.OpenAsync(); var (dbCommand, dbDataParameter) = CreateReadCommand(pooledConnection); @@ -56,7 +56,7 @@ public static World[] LoadMultipleQueriesRows(int count) { for (int i = 0; i < count; i++) { - worlds[i] = ReadSingleRow(dbCommand); + worlds[i] = await ReadSingleRow(dbCommand); dbDataParameter.Value = _random.Next(1, 10001); } } @@ -64,18 +64,18 @@ public static World[] LoadMultipleQueriesRows(int count) return worlds; } - public static List LoadFortunesRows() + public static async Task> LoadFortunesRows() { var fortunes = new List(); - using var pooledConnection = DbConnections.GetConnection(DbProviderFactory.ConnectionString); - pooledConnection.Open(); + using var pooledConnection = new DbConnection(DbProviderFactory.ConnectionString); + await pooledConnection.OpenAsync(); var dbCommand = new DbCommand("SELECT * FROM fortune", pooledConnection); using (dbCommand) { - IDataReader dataReader = dbCommand.ExecuteReader(CommandBehavior.SingleResult & CommandBehavior.SequentialAccess); + IDataReader dataReader = await dbCommand.ExecuteReaderAsync(CommandBehavior.SingleResult & CommandBehavior.SequentialAccess); while (dataReader.Read()) { @@ -97,25 +97,25 @@ public static List LoadFortunesRows() return fortunes; } - public static World[] LoadMultipleUpdatesRows(int count) + public static async Task LoadMultipleUpdatesRows(int count) { var worlds = new World[count]; - using var pooledConnection = DbConnections.GetConnection(DbProviderFactory.ConnectionString); - pooledConnection.Open(); + using var pooledConnection = new DbConnection(DbProviderFactory.ConnectionString, true); + await pooledConnection.OpenAsync(); - var (queryCommand, dbDataParameter) = CreateReadCommand(pooledConnection, true); + var (queryCommand, dbDataParameter) = CreateReadCommand(pooledConnection); using (queryCommand) { for (int i = 0; i < count; i++) { - worlds[i] = ReadSingleRow(queryCommand); + worlds[i] = await ReadSingleRow(queryCommand); dbDataParameter.Value = _random.Next(1, 10001); } } - using var updateCommand = new DbCommand(BatchUpdateString.Query(count), pooledConnection, true); + using var updateCommand = new DbCommand(BatchUpdateString.Query(count), pooledConnection); var ids = BatchUpdateString.Ids; var randoms = BatchUpdateString.Randoms; @@ -152,13 +152,6 @@ internal static (DbCommand dbCommand, IDbDataParameter dbDataParameter) CreateRe return (dbCommand, dbCommand.CreateParameter("Id", DbType.Int32, _random.Next(1, 10001))); } - internal static (DbCommand dbCommand, IDbDataParameter dbDataParameter) CreateReadCommand(DbConnection pooledConnection, bool keyed) - { - DbCommand dbCommand = new DbCommand("SELECT * FROM world WHERE id=?", pooledConnection, keyed); - - return (dbCommand, dbCommand.CreateParameter("Id", DbType.Int32, _random.Next(1, 10001))); - } - internal static (DbCommand dbCommand, IDbDataParameter dbDataParameter) CreateReadCommandById(DbConnection pooledConnection, int id) { DbCommand dbCommand = new DbCommand("SELECT * FROM world WHERE id=?", pooledConnection); @@ -166,9 +159,9 @@ internal static (DbCommand dbCommand, IDbDataParameter dbDataParameter) CreateRe return (dbCommand, dbCommand.CreateParameter("Id", DbType.Int32, id)); } - internal static World ReadSingleRow(DbCommand dbCommand) + internal static async Task ReadSingleRow(DbCommand dbCommand) { - var dataReader = dbCommand.ExecuteReader(CommandBehavior.SingleRow & CommandBehavior.SequentialAccess); + var dataReader = await dbCommand.ExecuteReaderAsync(CommandBehavior.SingleRow & CommandBehavior.SequentialAccess); dataReader.Read(); @@ -183,7 +176,7 @@ internal static World ReadSingleRow(DbCommand dbCommand) return world; } - public static World[] ReadMultipleRows(int count) + public static async Task ReadMultipleRows(int count) { int j = 0; var ids = BatchUpdateString.Ids; @@ -206,8 +199,8 @@ public static World[] ReadMultipleRows(int count) queryString = _queriesMultipleRows[count] = StringBuilderCache.GetStringAndRelease(stringBuilder); } - using var pooledConnection = DbConnections.GetConnection(DbProviderFactory.ConnectionString); - pooledConnection.Open(); + using var pooledConnection = new DbConnection(DbProviderFactory.ConnectionString); + await pooledConnection.OpenAsync(); using var dbCommand = new DbCommand(queryString, pooledConnection); @@ -216,7 +209,7 @@ public static World[] ReadMultipleRows(int count) dbCommand.CreateParameter(ids[i], DbType.Int32, _random.Next(1, 10001)); } - var dataReader = dbCommand.ExecuteReader(CommandBehavior.Default & CommandBehavior.SequentialAccess); + var dataReader = await dbCommand.ExecuteReaderAsync(CommandBehavior.Default & CommandBehavior.SequentialAccess); do { @@ -229,7 +222,7 @@ public static World[] ReadMultipleRows(int count) }; j++; - } while (dataReader.NextResult()); + } while (await dataReader.NextResultAsync()); dataReader.Close(); From 9e89ea26ffe49a4005fb4667a40f2cf35e485842 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 30 Sep 2024 19:47:06 +0000 Subject: [PATCH 136/204] Bump io.undertow:undertow-core in /frameworks/Java/undertow-jersey Bumps [io.undertow:undertow-core](https://github.com/undertow-io/undertow) from 2.3.14.Final to 2.3.16.Final. - [Release notes](https://github.com/undertow-io/undertow/releases) - [Commits](https://github.com/undertow-io/undertow/compare/2.3.14.Final...2.3.16.Final) --- updated-dependencies: - dependency-name: io.undertow:undertow-core dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- frameworks/Java/undertow-jersey/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frameworks/Java/undertow-jersey/pom.xml b/frameworks/Java/undertow-jersey/pom.xml index bf4603735ca..6c2ced9b7a1 100644 --- a/frameworks/Java/undertow-jersey/pom.xml +++ b/frameworks/Java/undertow-jersey/pom.xml @@ -174,7 +174,7 @@ io.undertow undertow-core - 2.3.14.Final + 2.3.16.Final From 5b93494b422b3c42136562cf6019dc220654b6e9 Mon Sep 17 00:00:00 2001 From: Anton Kirilov Date: Wed, 2 Oct 2024 00:34:53 +0100 Subject: [PATCH 137/204] H2O: Use the PostgreSQL project's Apt repository for libpq (#9294) --- frameworks/C/h2o/h2o.dockerfile | 44 ++++++++++++++++++++------------- 1 file changed, 27 insertions(+), 17 deletions(-) diff --git a/frameworks/C/h2o/h2o.dockerfile b/frameworks/C/h2o/h2o.dockerfile index 976c938337a..109c5e4375a 100644 --- a/frameworks/C/h2o/h2o.dockerfile +++ b/frameworks/C/h2o/h2o.dockerfile @@ -6,19 +6,28 @@ FROM "ubuntu:${UBUNTU_VERSION}" AS compile ARG DEBIAN_FRONTEND=noninteractive RUN apt-get -yqq update && \ + apt-get -yqq install \ + ca-certificates \ + curl \ + lsb-release && \ + install -dm755 /usr/share/postgresql-common/pgdg && \ + curl --fail -LSso /usr/share/postgresql-common/pgdg/apt.postgresql.org.asc \ + "https://www.postgresql.org/media/keys/ACCC4CF8.asc" && \ + sh -c 'echo "deb [signed-by=/usr/share/postgresql-common/pgdg/apt.postgresql.org.asc] \ + https://apt.postgresql.org/pub/repos/apt $(lsb_release -cs)-pgdg main" > \ + /etc/apt/sources.list.d/pgdg.list' && \ + apt-get -yqq update && \ apt-get -yqq install \ autoconf \ bison \ cmake \ - curl \ flex \ g++ \ libbpfcc-dev \ libbrotli-dev \ libcap-dev \ - libicu-dev \ libnuma-dev \ - libreadline-dev \ + libpq-dev \ libssl-dev \ libtool \ libuv1-dev \ @@ -57,18 +66,6 @@ RUN curl -LSs "https://github.com/x86-64/mustache-c/archive/${MUSTACHE_C_REVISIO CFLAGS="-flto -march=native -mtune=native -O3" ./autogen.sh && \ make -j "$(nproc)" install -ARG POSTGRESQL_VERSION=a37bb7c13995b834095d9d064cad1023a6f99b10 - -WORKDIR /tmp/postgresql-build -RUN curl -LSs "https://github.com/postgres/postgres/archive/${POSTGRESQL_VERSION}.tar.gz" | \ - tar --strip-components=1 -xz && \ - CFLAGS="-flto -march=native -mtune=native -O3" ./configure \ - --includedir=/usr/local/include/postgresql \ - --prefix=/usr/local \ - --with-ssl=openssl && \ - make -j "$(nproc)" -C src/include install && \ - make -j "$(nproc)" -C src/interfaces/libpq install - ARG H2O_APP_PREFIX WORKDIR /tmp/build COPY CMakeLists.txt ../ @@ -85,15 +82,28 @@ RUN cmake \ FROM "ubuntu:${UBUNTU_VERSION}" +ARG POSTGRESQL_VERSION=17 + ARG DEBIAN_FRONTEND=noninteractive RUN apt-get -yqq update && \ + apt-get -yqq install \ + ca-certificates \ + curl \ + lsb-release && \ + install -dm755 /usr/share/postgresql-common/pgdg && \ + curl --fail -LSso /usr/share/postgresql-common/pgdg/apt.postgresql.org.asc \ + "https://www.postgresql.org/media/keys/ACCC4CF8.asc" && \ + sh -c 'echo "deb [signed-by=/usr/share/postgresql-common/pgdg/apt.postgresql.org.asc] \ + https://apt.postgresql.org/pub/repos/apt $(lsb_release -cs)-pgdg main" > \ + /etc/apt/sources.list.d/pgdg.list' && \ + apt-get -yqq update && \ apt-get -yqq install \ libnuma1 \ - libyajl2 + libyajl2 \ + "postgresql-client-${POSTGRESQL_VERSION}" ARG H2O_APP_PREFIX COPY --from=compile "${H2O_APP_PREFIX}" "${H2O_APP_PREFIX}/" COPY --from=compile /usr/local/lib/libmustache_c.so "${H2O_APP_PREFIX}/lib/" -COPY --from=compile /usr/local/lib/libpq.so.5.17 "${H2O_APP_PREFIX}/lib/libpq.so.5" ENV LD_LIBRARY_PATH="${H2O_APP_PREFIX}/lib" EXPOSE 8080 ARG BENCHMARK_ENV From b03e526dbcf64e3e68ba7aa9f79bbf8d0db2bb25 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Deleuze?= Date: Wed, 2 Oct 2024 01:35:07 +0200 Subject: [PATCH 138/204] New round of Spring optimizations (#9288) * New round of spring optimizations - Upgrade to Spring Boot 3.3.4 - Remove the JPA variant that is not competitive and introduces additional processing not needed in other variants - Use batched update in the JDBC variant (compliant with the test requirements) - Set Hikari maximum pool size to 256 - Switch to jstachio for view rendering * New round of spring-webflux optimizations - Upgrade to Spring Boot 3.3.4 - Disable Netty leak detection - Turn a flapMap operation to a map - Switch to jstachio for view rendering - Remove unused JdbcDbRepository class - Set R2DBC maximum pool size to 256 - Polishing --- frameworks/Java/spring-webflux/pom.xml | 28 ++++++-- .../spring-webflux-mongo.dockerfile | 2 +- .../spring-webflux/spring-webflux.dockerfile | 2 +- .../src/main/java/benchmark/App.java | 5 +- .../main/java/benchmark/model/Fortune.java | 13 ++-- .../main/java/benchmark/model/Message.java | 15 ---- .../src/main/java/benchmark/model/World.java | 1 + .../benchmark/repository/DbRepository.java | 1 + .../repository/JdbcDbRepository.java | 63 ---------------- .../main/java/benchmark/web/DbHandler.java | 28 ++++---- .../src/main/java/benchmark/web/Fortunes.java | 10 +++ .../src/main/resources/application.yml | 4 +- .../{templates => }/fortunes.mustache | 0 frameworks/Java/spring/README.md | 4 +- frameworks/Java/spring/benchmark_config.json | 21 ------ frameworks/Java/spring/pom.xml | 26 +++++-- frameworks/Java/spring/spring-jpa.dockerfile | 15 ---- .../Java/spring/src/main/java/hello/App.java | 21 +----- .../spring/src/main/java/hello/JpaConfig.java | 12 ---- .../main/java/hello/UpdateWorldService.java | 9 --- .../java/hello/UpdateWorldServiceImpl.java | 43 ----------- .../spring/src/main/java/hello/Utils.java | 19 +++++ .../java/hello/jpa/FortuneRepository.java | 12 ---- .../main/java/hello/jpa/JpaDbRepository.java | 38 ---------- .../main/java/hello/jpa/WorldRepository.java | 12 ---- .../src/main/java/hello/model/Fortune.java | 26 +++---- .../src/main/java/hello/model/Message.java | 15 ---- .../src/main/java/hello/model/World.java | 14 ++-- .../java/hello/repository/DbRepository.java | 3 +- .../hello/repository/JdbcDbRepository.java | 36 ++++++---- .../hello/repository/MongoDbRepository.java | 18 ++++- .../src/main/java/hello/web/DbHandler.java | 72 ++++++++----------- .../src/main/java/hello/web/Fortunes.java | 10 +++ .../spring/src/main/resources/application.yml | 34 +++------ .../{templates => }/fortunes.mustache | 0 35 files changed, 210 insertions(+), 422 deletions(-) delete mode 100644 frameworks/Java/spring-webflux/src/main/java/benchmark/model/Message.java delete mode 100644 frameworks/Java/spring-webflux/src/main/java/benchmark/repository/JdbcDbRepository.java create mode 100644 frameworks/Java/spring-webflux/src/main/java/benchmark/web/Fortunes.java rename frameworks/Java/spring-webflux/src/main/resources/{templates => }/fortunes.mustache (100%) delete mode 100644 frameworks/Java/spring/spring-jpa.dockerfile delete mode 100644 frameworks/Java/spring/src/main/java/hello/JpaConfig.java delete mode 100644 frameworks/Java/spring/src/main/java/hello/UpdateWorldService.java delete mode 100644 frameworks/Java/spring/src/main/java/hello/UpdateWorldServiceImpl.java create mode 100644 frameworks/Java/spring/src/main/java/hello/Utils.java delete mode 100644 frameworks/Java/spring/src/main/java/hello/jpa/FortuneRepository.java delete mode 100644 frameworks/Java/spring/src/main/java/hello/jpa/JpaDbRepository.java delete mode 100644 frameworks/Java/spring/src/main/java/hello/jpa/WorldRepository.java delete mode 100644 frameworks/Java/spring/src/main/java/hello/model/Message.java create mode 100644 frameworks/Java/spring/src/main/java/hello/web/Fortunes.java rename frameworks/Java/spring/src/main/resources/{templates => }/fortunes.mustache (100%) diff --git a/frameworks/Java/spring-webflux/pom.xml b/frameworks/Java/spring-webflux/pom.xml index c15b211c92d..500e9fc8e07 100644 --- a/frameworks/Java/spring-webflux/pom.xml +++ b/frameworks/Java/spring-webflux/pom.xml @@ -13,13 +13,12 @@ org.springframework.boot spring-boot-starter-parent - 3.3.3 + 3.3.4 - 21 - 21 - UTF-8 + 21 + 1.3.6 @@ -36,8 +35,16 @@ r2dbc-postgresql - org.springframework.boot - spring-boot-starter-mustache + io.jstach + jstachio + ${jstachio.version} + + + io.jstach + jstachio-apt + ${jstachio.version} + provided + true org.springframework.boot @@ -55,6 +62,15 @@ org.apache.maven.plugins maven-compiler-plugin + + + + io.jstach + jstachio-apt + ${jstachio.version} + + + diff --git a/frameworks/Java/spring-webflux/spring-webflux-mongo.dockerfile b/frameworks/Java/spring-webflux/spring-webflux-mongo.dockerfile index 41eedefa4c6..d565d1556c3 100644 --- a/frameworks/Java/spring-webflux/spring-webflux-mongo.dockerfile +++ b/frameworks/Java/spring-webflux/spring-webflux-mongo.dockerfile @@ -13,4 +13,4 @@ RUN java -Djarmode=tools -jar app.jar extract EXPOSE 8080 -CMD ["java", "-Dlogging.level.root=OFF", "-Dreactor.netty.http.server.lastFlushWhenNoRead=true", "-jar", "app/app.jar", "--spring.profiles.active=mongo"] \ No newline at end of file +CMD ["java", "-Dlogging.level.root=OFF", "-Dio.netty.leakDetection.level=disabled", "-Dreactor.netty.http.server.lastFlushWhenNoRead=true", "-jar", "app/app.jar", "--spring.profiles.active=mongo"] \ No newline at end of file diff --git a/frameworks/Java/spring-webflux/spring-webflux.dockerfile b/frameworks/Java/spring-webflux/spring-webflux.dockerfile index 6ff2ed4e537..e1cee08ff31 100644 --- a/frameworks/Java/spring-webflux/spring-webflux.dockerfile +++ b/frameworks/Java/spring-webflux/spring-webflux.dockerfile @@ -12,4 +12,4 @@ RUN java -Djarmode=tools -jar app.jar extract EXPOSE 8080 -CMD ["java", "-Dlogging.level.root=OFF", "-Dreactor.netty.http.server.lastFlushWhenNoRead=true", "-jar", "app/app.jar", "--spring.profiles.active=r2dbc"] +CMD ["java", "-Dlogging.level.root=OFF", "-Dio.netty.leakDetection.level=disabled", "-Dreactor.netty.http.server.lastFlushWhenNoRead=true", "-jar", "app/app.jar", "--spring.profiles.active=r2dbc"] diff --git a/frameworks/Java/spring-webflux/src/main/java/benchmark/App.java b/frameworks/Java/spring-webflux/src/main/java/benchmark/App.java index c574863a9a9..3ba49056611 100644 --- a/frameworks/Java/spring-webflux/src/main/java/benchmark/App.java +++ b/frameworks/Java/spring-webflux/src/main/java/benchmark/App.java @@ -11,7 +11,6 @@ import org.springframework.web.reactive.function.server.RouterFunction; import org.springframework.web.reactive.function.server.RouterFunctions; import org.springframework.web.reactive.function.server.ServerResponse; -import org.springframework.web.reactive.result.view.ViewResolver; import org.springframework.web.server.WebHandler; import org.springframework.web.server.adapter.WebHttpHandlerBuilder; @@ -20,8 +19,8 @@ public class App { @Bean - public HttpHandler httpHandler(RouterFunction route, ServerFilter serverFilter, ViewResolver viewResolver) { - WebHandler webHandler = RouterFunctions.toWebHandler(route, HandlerStrategies.builder().viewResolver(viewResolver).build()); + public HttpHandler httpHandler(RouterFunction route, ServerFilter serverFilter) { + WebHandler webHandler = RouterFunctions.toWebHandler(route, HandlerStrategies.builder().build()); return WebHttpHandlerBuilder.webHandler(webHandler).filter(serverFilter).build(); } diff --git a/frameworks/Java/spring-webflux/src/main/java/benchmark/model/Fortune.java b/frameworks/Java/spring-webflux/src/main/java/benchmark/model/Fortune.java index 12ae17e0448..d66f56215fc 100644 --- a/frameworks/Java/spring-webflux/src/main/java/benchmark/model/Fortune.java +++ b/frameworks/Java/spring-webflux/src/main/java/benchmark/model/Fortune.java @@ -4,9 +4,11 @@ import org.springframework.data.mongodb.core.mapping.Document; @Document -public final class Fortune { +public final class Fortune implements Comparable { + @Id public int id; + public String message; public Fortune(int id, String message) { @@ -14,11 +16,8 @@ public Fortune(int id, String message) { this.message = message; } - public int getId() { - return id; - } - - public String getMessage() { - return message; + @Override + public int compareTo(final Fortune other) { + return message.compareTo(other.message); } } diff --git a/frameworks/Java/spring-webflux/src/main/java/benchmark/model/Message.java b/frameworks/Java/spring-webflux/src/main/java/benchmark/model/Message.java deleted file mode 100644 index 8a94c8d3ed1..00000000000 --- a/frameworks/Java/spring-webflux/src/main/java/benchmark/model/Message.java +++ /dev/null @@ -1,15 +0,0 @@ -package benchmark.model; - -public class Message { - - private final String message; - - public Message(String message) { - this.message = message; - } - - public String getMessage() { - return message; - } - -} \ No newline at end of file diff --git a/frameworks/Java/spring-webflux/src/main/java/benchmark/model/World.java b/frameworks/Java/spring-webflux/src/main/java/benchmark/model/World.java index 612c7fef03a..ab096a1e313 100644 --- a/frameworks/Java/spring-webflux/src/main/java/benchmark/model/World.java +++ b/frameworks/Java/spring-webflux/src/main/java/benchmark/model/World.java @@ -9,6 +9,7 @@ public final class World { @Id public int id; + @Field("randomNumber") public int randomnumber; diff --git a/frameworks/Java/spring-webflux/src/main/java/benchmark/repository/DbRepository.java b/frameworks/Java/spring-webflux/src/main/java/benchmark/repository/DbRepository.java index 20e753e317e..54b6d0d9d02 100644 --- a/frameworks/Java/spring-webflux/src/main/java/benchmark/repository/DbRepository.java +++ b/frameworks/Java/spring-webflux/src/main/java/benchmark/repository/DbRepository.java @@ -6,6 +6,7 @@ import reactor.core.publisher.Mono; public interface DbRepository { + Mono getWorld(int id); Mono findAndUpdateWorld(int id, int randomNumber); diff --git a/frameworks/Java/spring-webflux/src/main/java/benchmark/repository/JdbcDbRepository.java b/frameworks/Java/spring-webflux/src/main/java/benchmark/repository/JdbcDbRepository.java deleted file mode 100644 index 5e159f816ed..00000000000 --- a/frameworks/Java/spring-webflux/src/main/java/benchmark/repository/JdbcDbRepository.java +++ /dev/null @@ -1,63 +0,0 @@ -package benchmark.repository; - -import benchmark.model.Fortune; -import benchmark.model.World; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.context.annotation.Profile; -import org.springframework.jdbc.core.JdbcTemplate; -import org.springframework.stereotype.Component; -import reactor.core.publisher.Flux; -import reactor.core.publisher.Mono; -import reactor.core.scheduler.Scheduler; - -@Component -@Profile("jdbc") -public class JdbcDbRepository implements DbRepository { - private final Logger log = LoggerFactory.getLogger(getClass()); - private final JdbcTemplate jdbcTemplate; - private final Scheduler scheduler; - - public JdbcDbRepository(JdbcTemplate jdbcTemplate, Scheduler scheduler) { - this.jdbcTemplate = jdbcTemplate; - this.scheduler = scheduler; - } - - @Override - public Mono getWorld(int id) { - log.debug("getWorld({})", id); - return Mono.fromCallable(() -> { - return jdbcTemplate.queryForObject( - "SELECT * FROM world WHERE id = ?", - (rs, rn) -> new World(rs.getInt("id"), rs.getInt("randomnumber")), - id); - }).subscribeOn(scheduler); - } - - private Mono updateWorld(World world) { - return Mono.fromCallable(() -> { - jdbcTemplate.update( - "UPDATE world SET randomnumber = ? WHERE id = ?", - world.randomnumber, - world.id); - return world; - }).subscribeOn(scheduler); - } - - @Override - public Mono findAndUpdateWorld(int id, int randomNumber) { - return getWorld(id).flatMap(world -> { - world.randomnumber = randomNumber; - return updateWorld(world); - }); - } - - @Override - public Flux fortunes() { - return Mono.fromCallable(() -> { - return jdbcTemplate.query( - "SELECT * FROM fortune", - (rs, rn) -> new Fortune(rs.getInt("id"), rs.getString("message"))); - }).subscribeOn(scheduler).flatMapIterable(fortunes -> fortunes); - } -} \ No newline at end of file diff --git a/frameworks/Java/spring-webflux/src/main/java/benchmark/web/DbHandler.java b/frameworks/Java/spring-webflux/src/main/java/benchmark/web/DbHandler.java index bafddaf83c6..970ace1d46d 100644 --- a/frameworks/Java/spring-webflux/src/main/java/benchmark/web/DbHandler.java +++ b/frameworks/Java/spring-webflux/src/main/java/benchmark/web/DbHandler.java @@ -1,26 +1,27 @@ package benchmark.web; -import java.util.Collections; import java.util.List; import java.util.concurrent.ThreadLocalRandom; import benchmark.model.Fortune; import benchmark.model.World; import benchmark.repository.DbRepository; +import io.jstach.jstachio.JStachio; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; import org.springframework.core.ParameterizedTypeReference; +import org.springframework.http.HttpHeaders; import org.springframework.http.MediaType; import org.springframework.stereotype.Component; import org.springframework.web.reactive.function.server.ServerRequest; import org.springframework.web.reactive.function.server.ServerResponse; -import static java.util.Comparator.comparing; - @Component public class DbHandler { + private static final String CONTENT_TYPE_VALUE = "text/html; charset=utf-8"; + private final DbRepository dbRepository; public DbHandler(DbRepository dbRepository) { @@ -33,7 +34,7 @@ public Mono db(ServerRequest request) { .switchIfEmpty(Mono.error(new Exception("No World found with Id: " + id))); return ServerResponse.ok() - .contentType(MediaType.APPLICATION_JSON) + .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE) .body(world, World.class); } @@ -45,7 +46,7 @@ public Mono queries(ServerRequest request) { .collectList(); return ServerResponse.ok() - .contentType(MediaType.APPLICATION_JSON) + .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE) .body(worlds, new ParameterizedTypeReference>() { }); } @@ -71,20 +72,19 @@ public Mono updates(ServerRequest request) { .collectList(); return ServerResponse.ok() - .contentType(MediaType.APPLICATION_JSON) + .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE) .body(worlds, new ParameterizedTypeReference>() { }); } public Mono fortunes(ServerRequest request) { - Mono> result = dbRepository.fortunes().collectList().flatMap(fortunes -> { - fortunes.add(new Fortune(0, "Additional fortune added at request time.")); - fortunes.sort(comparing(fortune -> fortune.message)); - return Mono.just(fortunes); - }); - - return ServerResponse.ok() - .render("fortunes", Collections.singletonMap("fortunes", result)); + return dbRepository.fortunes() + .concatWith(Mono.just(new Fortune(0, "Additional fortune added at request time."))) + .collectSortedList() + .flatMap(fortunes -> + ServerResponse.ok() + .header(HttpHeaders.CONTENT_TYPE, CONTENT_TYPE_VALUE) + .bodyValue(JStachio.render(new Fortunes(fortunes)))); } private static int randomWorldNumber() { diff --git a/frameworks/Java/spring-webflux/src/main/java/benchmark/web/Fortunes.java b/frameworks/Java/spring-webflux/src/main/java/benchmark/web/Fortunes.java new file mode 100644 index 00000000000..d8fc3dd7e2d --- /dev/null +++ b/frameworks/Java/spring-webflux/src/main/java/benchmark/web/Fortunes.java @@ -0,0 +1,10 @@ +package benchmark.web; + +import java.util.List; + +import benchmark.model.Fortune; +import io.jstach.jstache.JStache; + +@JStache(path = "fortunes.mustache") +public record Fortunes(List fortunes) { +} diff --git a/frameworks/Java/spring-webflux/src/main/resources/application.yml b/frameworks/Java/spring-webflux/src/main/resources/application.yml index af7743831e3..45ca20c7d80 100755 --- a/frameworks/Java/spring-webflux/src/main/resources/application.yml +++ b/frameworks/Java/spring-webflux/src/main/resources/application.yml @@ -15,7 +15,9 @@ spring: r2dbc: username: ${database.username} password: ${database.password} - url: r2dbc:postgresql://${database.host}:${database.port}/${database.name} + url: r2dbc:postgresql://${database.host}:${database.port}/${database.name}?loggerLevel=OFF&disableColumnSanitiser=true&assumeMinServerVersion=16&sslmode=disable + pool: + max-size: 256 --- spring: diff --git a/frameworks/Java/spring-webflux/src/main/resources/templates/fortunes.mustache b/frameworks/Java/spring-webflux/src/main/resources/fortunes.mustache similarity index 100% rename from frameworks/Java/spring-webflux/src/main/resources/templates/fortunes.mustache rename to frameworks/Java/spring-webflux/src/main/resources/fortunes.mustache diff --git a/frameworks/Java/spring/README.md b/frameworks/Java/spring/README.md index 8e25a585d44..742649fff7e 100644 --- a/frameworks/Java/spring/README.md +++ b/frameworks/Java/spring/README.md @@ -2,9 +2,7 @@ This is the Spring MVC portion of a [benchmarking test suite](../) comparing a variety of web development platforms. -An embedded undertow is used for the web server, with nearly everything configured with default settings. -The only thing changed is Hikari can use up to (2 * cores count) connections (the default is 10). -See [About-Pool-Sizing](https://github.com/brettwooldridge/HikariCP/wiki/About-Pool-Sizing) +An embedded undertow is used for the web server. There are two implementations : * For postgresql access, JdbcTemplate is used. See [JdbcDbRepository](src/main/java/hello/JdbcDbRepository.java). diff --git a/frameworks/Java/spring/benchmark_config.json b/frameworks/Java/spring/benchmark_config.json index 615c4a478ca..72362984811 100644 --- a/frameworks/Java/spring/benchmark_config.json +++ b/frameworks/Java/spring/benchmark_config.json @@ -24,27 +24,6 @@ "notes": "", "versus": "" }, - "jpa": { - "db_url": "/db", - "query_url": "/queries?queries=", - "fortune_url": "/fortunes", - "update_url": "/updates?queries=", - "port": 8080, - "approach": "Realistic", - "classification": "Fullstack", - "database": "Postgres", - "framework": "spring", - "language": "Java", - "flavor": "None", - "orm": "Full", - "platform": "Servlet", - "webserver": "Undertow", - "os": "Linux", - "database_os": "Linux", - "display_name": "spring-jpa", - "notes": "", - "versus": "spring" - }, "mongo": { "db_url": "/db", "query_url": "/queries?queries=", diff --git a/frameworks/Java/spring/pom.xml b/frameworks/Java/spring/pom.xml index 4a8d36e9749..6c9341fed54 100644 --- a/frameworks/Java/spring/pom.xml +++ b/frameworks/Java/spring/pom.xml @@ -11,11 +11,12 @@ org.springframework.boot spring-boot-starter-parent - 3.3.3 + 3.3.4 21 + 1.3.6 @@ -35,15 +36,23 @@ org.springframework.boot - spring-boot-starter-data-jpa + spring-boot-starter-jdbc org.springframework.boot spring-boot-starter-data-mongodb - org.springframework.boot - spring-boot-starter-mustache + io.jstach + jstachio + ${jstachio.version} + + + io.jstach + jstachio-apt + ${jstachio.version} + provided + true @@ -61,6 +70,15 @@ org.apache.maven.plugins maven-compiler-plugin + + + + io.jstach + jstachio-apt + ${jstachio.version} + + + diff --git a/frameworks/Java/spring/spring-jpa.dockerfile b/frameworks/Java/spring/spring-jpa.dockerfile deleted file mode 100644 index 0598e9c1f28..00000000000 --- a/frameworks/Java/spring/spring-jpa.dockerfile +++ /dev/null @@ -1,15 +0,0 @@ -FROM maven:3.9.5-eclipse-temurin-21 as maven -WORKDIR /spring -COPY src src -COPY pom.xml pom.xml -RUN mvn package -q - -FROM bellsoft/liberica-openjre-debian:21 -WORKDIR /spring -COPY --from=maven /spring/target/hello-spring-1.0-SNAPSHOT.jar app.jar -# See https://docs.spring.io/spring-boot/reference/packaging/efficient.html -RUN java -Djarmode=tools -jar app.jar extract - -EXPOSE 8080 - -CMD ["java", "-XX:+DisableExplicitGC", "-XX:+UseStringDeduplication", "-Dlogging.level.root=OFF", "-jar", "app/app.jar", "--spring.profiles.active=jpa"] \ No newline at end of file diff --git a/frameworks/Java/spring/src/main/java/hello/App.java b/frameworks/Java/spring/src/main/java/hello/App.java index 0484b46517e..da87b679f87 100644 --- a/frameworks/Java/spring/src/main/java/hello/App.java +++ b/frameworks/Java/spring/src/main/java/hello/App.java @@ -1,17 +1,10 @@ package hello; -import javax.sql.DataSource; - import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties; import org.springframework.boot.context.event.ApplicationReadyEvent; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Profile; import org.springframework.context.event.EventListener; -import com.zaxxer.hikari.HikariDataSource; - @SpringBootApplication public class App { @@ -20,18 +13,8 @@ public static void main(String[] args) { } @EventListener(ApplicationReadyEvent.class) - public void runAfterStartup() { - System.out.println("Application is ready"); - } - - @Bean - @Profile({ "jdbc", "jpa" }) - DataSource datasource(DataSourceProperties dataSourceProperties) { - HikariDataSource dataSource = dataSourceProperties.initializeDataSourceBuilder().type(HikariDataSource.class) - .build(); - dataSource.setMaximumPoolSize(Runtime.getRuntime().availableProcessors() * 2); - - return dataSource; + public void runAfterStartup() { + System.out.println("Application is ready"); } } diff --git a/frameworks/Java/spring/src/main/java/hello/JpaConfig.java b/frameworks/Java/spring/src/main/java/hello/JpaConfig.java deleted file mode 100644 index c5b8576acab..00000000000 --- a/frameworks/Java/spring/src/main/java/hello/JpaConfig.java +++ /dev/null @@ -1,12 +0,0 @@ -package hello; - -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.Profile; -import org.springframework.data.jpa.repository.config.EnableJpaRepositories; - -@Profile("jpa") -@Configuration -@EnableJpaRepositories(basePackages = "hello.jpa") -public class JpaConfig { - -} diff --git a/frameworks/Java/spring/src/main/java/hello/UpdateWorldService.java b/frameworks/Java/spring/src/main/java/hello/UpdateWorldService.java deleted file mode 100644 index 11c6568c076..00000000000 --- a/frameworks/Java/spring/src/main/java/hello/UpdateWorldService.java +++ /dev/null @@ -1,9 +0,0 @@ -package hello; - -import hello.model.World; - -public interface UpdateWorldService { - - World updateWorld(int worldId); - -} diff --git a/frameworks/Java/spring/src/main/java/hello/UpdateWorldServiceImpl.java b/frameworks/Java/spring/src/main/java/hello/UpdateWorldServiceImpl.java deleted file mode 100644 index 2bd4304a9ee..00000000000 --- a/frameworks/Java/spring/src/main/java/hello/UpdateWorldServiceImpl.java +++ /dev/null @@ -1,43 +0,0 @@ -package hello; - -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -import hello.web.DbHandler; -import hello.web.WebmvcRouter; -import hello.model.World; -import hello.repository.DbRepository; - -@Service -public class UpdateWorldServiceImpl implements UpdateWorldService { - - private DbRepository dbRepository; - - public UpdateWorldServiceImpl(DbRepository dbRepository) { - this.dbRepository = dbRepository; - } - - @Override - @Transactional - public World updateWorld(int worldId) { - var world = dbRepository.getWorld(worldId); - // Ensure that the new random number is not equal to the old one. - // That would cause the JPA-based implementation to avoid sending the - // UPDATE query to the database, which would violate the test - // requirements. - - // Locally the records doesn't exist, maybe in the yours is ok but we need to - // make this check - if (world == null) { - return null; - } - - int newRandomNumber; - do { - newRandomNumber = DbHandler.randomWorldNumber(); - } while (newRandomNumber == world.randomnumber); - - return dbRepository.updateWorld(world, newRandomNumber); - } - -} diff --git a/frameworks/Java/spring/src/main/java/hello/Utils.java b/frameworks/Java/spring/src/main/java/hello/Utils.java new file mode 100644 index 00000000000..fbb1216624f --- /dev/null +++ b/frameworks/Java/spring/src/main/java/hello/Utils.java @@ -0,0 +1,19 @@ +package hello; + +import java.util.concurrent.ThreadLocalRandom; +import java.util.stream.IntStream; + +abstract public class Utils { + + private static final int MIN_WORLD_NUMBER = 1; + private static final int MAX_WORLD_NUMBER_PLUS_ONE = 10_001; + + public static int randomWorldNumber() { + return ThreadLocalRandom.current().nextInt(MIN_WORLD_NUMBER, MAX_WORLD_NUMBER_PLUS_ONE); + } + + public static IntStream randomWorldNumbers() { + return ThreadLocalRandom.current().ints(MIN_WORLD_NUMBER, MAX_WORLD_NUMBER_PLUS_ONE).distinct(); + } + +} diff --git a/frameworks/Java/spring/src/main/java/hello/jpa/FortuneRepository.java b/frameworks/Java/spring/src/main/java/hello/jpa/FortuneRepository.java deleted file mode 100644 index 30dea98cc27..00000000000 --- a/frameworks/Java/spring/src/main/java/hello/jpa/FortuneRepository.java +++ /dev/null @@ -1,12 +0,0 @@ -package hello.jpa; - -import org.springframework.context.annotation.Profile; -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.stereotype.Repository; - -import hello.model.Fortune; - -@Repository -@Profile("jpa") -public interface FortuneRepository extends JpaRepository { -} diff --git a/frameworks/Java/spring/src/main/java/hello/jpa/JpaDbRepository.java b/frameworks/Java/spring/src/main/java/hello/jpa/JpaDbRepository.java deleted file mode 100644 index 2b58841a035..00000000000 --- a/frameworks/Java/spring/src/main/java/hello/jpa/JpaDbRepository.java +++ /dev/null @@ -1,38 +0,0 @@ -package hello.jpa; - -import java.util.List; - -import org.springframework.context.annotation.Profile; -import org.springframework.stereotype.Service; - -import hello.model.Fortune; -import hello.model.World; -import hello.repository.DbRepository; - -@Service -@Profile("jpa") -public class JpaDbRepository implements DbRepository { - private final WorldRepository worldRepository; - private final FortuneRepository fortuneRepository; - - public JpaDbRepository(WorldRepository worldRepository, FortuneRepository fortuneRepository) { - this.worldRepository = worldRepository; - this.fortuneRepository = fortuneRepository; - } - - @Override - public World getWorld(int id) { - return worldRepository.findById(id).orElse(null); - } - - @Override - public World updateWorld(World world, int randomNumber) { - world.randomnumber = randomNumber; - return worldRepository.save(world); - } - - @Override - public List fortunes() { - return fortuneRepository.findAll(); - } -} diff --git a/frameworks/Java/spring/src/main/java/hello/jpa/WorldRepository.java b/frameworks/Java/spring/src/main/java/hello/jpa/WorldRepository.java deleted file mode 100644 index 70361aa40d6..00000000000 --- a/frameworks/Java/spring/src/main/java/hello/jpa/WorldRepository.java +++ /dev/null @@ -1,12 +0,0 @@ -package hello.jpa; - -import org.springframework.context.annotation.Profile; -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.stereotype.Repository; - -import hello.model.World; - -@Repository -@Profile("jpa") -public interface WorldRepository extends JpaRepository { -} diff --git a/frameworks/Java/spring/src/main/java/hello/model/Fortune.java b/frameworks/Java/spring/src/main/java/hello/model/Fortune.java index e4ff559610a..a628d3c755f 100644 --- a/frameworks/Java/spring/src/main/java/hello/model/Fortune.java +++ b/frameworks/Java/spring/src/main/java/hello/model/Fortune.java @@ -1,33 +1,25 @@ package hello.model; -import jakarta.persistence.Entity; - import org.springframework.data.annotation.Id; import org.springframework.data.mongodb.core.mapping.Document; import org.springframework.data.mongodb.core.mapping.Field; @Document -@Entity -public final class Fortune { +public final class Fortune implements Comparable{ + @Id - @jakarta.persistence.Id - public int id; - @Field("message") - public String message; + public final int id; - protected Fortune() { - } + @Field("message") + public final String message; public Fortune(int id, String message) { this.id = id; this.message = message; } - public int getId() { - return id; - } - - public String getMessage() { - return message; + @Override + public int compareTo(final Fortune other) { + return message.compareTo(other.message); } -} \ No newline at end of file +} diff --git a/frameworks/Java/spring/src/main/java/hello/model/Message.java b/frameworks/Java/spring/src/main/java/hello/model/Message.java deleted file mode 100644 index 4c675c8a162..00000000000 --- a/frameworks/Java/spring/src/main/java/hello/model/Message.java +++ /dev/null @@ -1,15 +0,0 @@ -package hello.model; - -public class Message { - - private final String message; - - public Message(String message) { - this.message = message; - } - - public String getMessage() { - return message; - } - -} \ No newline at end of file diff --git a/frameworks/Java/spring/src/main/java/hello/model/World.java b/frameworks/Java/spring/src/main/java/hello/model/World.java index 2855df8a5d8..762e9e622ce 100644 --- a/frameworks/Java/spring/src/main/java/hello/model/World.java +++ b/frameworks/Java/spring/src/main/java/hello/model/World.java @@ -1,26 +1,22 @@ package hello.model; -import jakarta.persistence.Entity; - import org.springframework.data.annotation.Id; import org.springframework.data.mongodb.core.mapping.Document; import org.springframework.data.mongodb.core.mapping.Field; @Document -@Entity public final class World { @Id - @jakarta.persistence.Id public int id; + @Field("randomNumber") - public int randomnumber; + public int randomNumber; - protected World() { - } - public World(int id, int randomnumber) { + public World(int id, int randomNumber) { this.id = id; - this.randomnumber = randomnumber; + this.randomNumber = randomNumber; } + } \ No newline at end of file diff --git a/frameworks/Java/spring/src/main/java/hello/repository/DbRepository.java b/frameworks/Java/spring/src/main/java/hello/repository/DbRepository.java index 5cfa8c7d5c3..d7733754c2c 100644 --- a/frameworks/Java/spring/src/main/java/hello/repository/DbRepository.java +++ b/frameworks/Java/spring/src/main/java/hello/repository/DbRepository.java @@ -6,9 +6,10 @@ import hello.model.World; public interface DbRepository { + World getWorld(int id); - World updateWorld(World world, int randomNumber); + void updateWorlds(List worlds); List fortunes(); } diff --git a/frameworks/Java/spring/src/main/java/hello/repository/JdbcDbRepository.java b/frameworks/Java/spring/src/main/java/hello/repository/JdbcDbRepository.java index f1dcdae0352..bc706e232c8 100644 --- a/frameworks/Java/spring/src/main/java/hello/repository/JdbcDbRepository.java +++ b/frameworks/Java/spring/src/main/java/hello/repository/JdbcDbRepository.java @@ -1,10 +1,15 @@ package hello.repository; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.ArrayList; import java.util.List; import org.springframework.context.annotation.Profile; import org.springframework.dao.EmptyResultDataAccessException; import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.core.ParameterizedPreparedStatementSetter; import org.springframework.stereotype.Repository; import hello.model.Fortune; @@ -22,27 +27,34 @@ public JdbcDbRepository(JdbcTemplate jdbcTemplate) { @Override public World getWorld(int id) { try { - return jdbcTemplate.queryForObject("SELECT * FROM world WHERE id = ?", - (rs, rn) -> new World(rs.getInt("id"), rs.getInt("randomnumber")), id); + return jdbcTemplate.queryForObject("SELECT id, randomnumber FROM world WHERE id = ?", + (rs, rn) -> new World(rs.getInt(1), rs.getInt(2)), id); } catch (EmptyResultDataAccessException e) { return null; } } - private World updateWorld(World world) { - jdbcTemplate.update("UPDATE world SET randomnumber = ? WHERE id = ?", world.randomnumber, world.id); - return world; - } - @Override - public World updateWorld(World world, int randomNumber) { - world.randomnumber = randomNumber; - return updateWorld(world); + public void updateWorlds(List worlds) { + jdbcTemplate.batchUpdate("UPDATE world SET randomnumber = ? WHERE id = ?", worlds, worlds.size(), new ParameterizedPreparedStatementSetter() { + @Override + public void setValues(PreparedStatement ps, World world) throws SQLException { + ps.setInt(1, world.randomNumber); + ps.setInt(2, world.id); + } + }); } @Override public List fortunes() { - return jdbcTemplate.query("SELECT * FROM fortune", - (rs, rn) -> new Fortune(rs.getInt("id"), rs.getString("message"))); + return jdbcTemplate.query(con -> con.prepareStatement("SELECT id, message FROM fortune", + ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY), rs -> { + List results = new ArrayList<>(); + while (rs.next()) { + results.add(new Fortune(rs.getInt(1), rs.getString(2))); + } + return results; + }); } + } diff --git a/frameworks/Java/spring/src/main/java/hello/repository/MongoDbRepository.java b/frameworks/Java/spring/src/main/java/hello/repository/MongoDbRepository.java index 66c81e64f1d..9b6b67c4c95 100644 --- a/frameworks/Java/spring/src/main/java/hello/repository/MongoDbRepository.java +++ b/frameworks/Java/spring/src/main/java/hello/repository/MongoDbRepository.java @@ -1,11 +1,18 @@ package hello.repository; +import java.util.ArrayList; import java.util.List; import org.springframework.context.annotation.Profile; +import org.springframework.data.mongodb.core.BulkOperations; import org.springframework.data.mongodb.core.MongoTemplate; +import org.springframework.data.mongodb.core.query.Criteria; +import org.springframework.data.mongodb.core.query.Query; +import org.springframework.data.mongodb.core.query.Update; import org.springframework.stereotype.Repository; +import com.mongodb.bulk.BulkWriteResult; +import hello.Utils; import hello.model.Fortune; import hello.model.World; @@ -24,9 +31,14 @@ public World getWorld(int id) { } @Override - public World updateWorld(World world, int randomNumber) { - world.randomnumber = randomNumber; - return mongoTemplate.save(world); + public void updateWorlds(List worlds) { + BulkOperations bulkOps = mongoTemplate.bulkOps(BulkOperations.BulkMode.UNORDERED, World.class); + for (World world : worlds) { + Query query = new Query().addCriteria(new Criteria("_id").is(world.id)); + Update update = new Update().set("randomNumber", world.randomNumber); + bulkOps.updateOne(query, update); + } + bulkOps.execute(); } @Override diff --git a/frameworks/Java/spring/src/main/java/hello/web/DbHandler.java b/frameworks/Java/spring/src/main/java/hello/web/DbHandler.java index 1611cf21170..affb752268f 100644 --- a/frameworks/Java/spring/src/main/java/hello/web/DbHandler.java +++ b/frameworks/Java/spring/src/main/java/hello/web/DbHandler.java @@ -1,83 +1,71 @@ package hello.web; -import java.util.concurrent.ThreadLocalRandom; -import java.util.stream.IntStream; +import java.util.Collections; +import java.util.List; -import hello.UpdateWorldService; +import hello.Utils; import hello.model.Fortune; import hello.model.World; import hello.repository.DbRepository; +import io.jstach.jstachio.JStachio; import org.springframework.http.HttpHeaders; import org.springframework.http.MediaType; import org.springframework.stereotype.Component; -import org.springframework.web.servlet.function.RenderingResponse; import org.springframework.web.servlet.function.ServerRequest; import org.springframework.web.servlet.function.ServerResponse; -import static java.util.Comparator.comparing; - @Component public class DbHandler { - private DbRepository dbRepository; - private UpdateWorldService updateWorldService; + private final DbRepository dbRepository; - public DbHandler(DbRepository dbRepository, UpdateWorldService updateWorldService) { + public DbHandler(DbRepository dbRepository) { this.dbRepository = dbRepository; - this.updateWorldService = updateWorldService; } ServerResponse db(ServerRequest request) { return ServerResponse.ok() - .contentType(MediaType.APPLICATION_JSON) - .body(dbRepository.getWorld(randomWorldNumber())); + .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE) + .body(dbRepository.getWorld(Utils.randomWorldNumber())); } ServerResponse queries(ServerRequest request) { - String queries = request.params().getFirst("queries"); - World[] worlds = randomWorldNumbers() - .mapToObj(dbRepository::getWorld).limit(parseQueryCount(queries)) + int queries = parseQueryCount(request.params().getFirst("queries")); + World[] worlds = Utils.randomWorldNumbers() + .mapToObj(dbRepository::getWorld).limit(queries) .toArray(World[]::new); return ServerResponse.ok() - .contentType(MediaType.APPLICATION_JSON) + .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE) .body(worlds); } ServerResponse updates(ServerRequest request) { - String queries = request.params().getFirst("queries"); - World[] worlds = randomWorldNumbers() - .mapToObj(id -> updateWorldService.updateWorld(id)) - .limit(parseQueryCount(queries)).toArray(World[]::new); + int queries = parseQueryCount(request.params().getFirst("queries")); + List worlds = Utils.randomWorldNumbers() + .mapToObj(id -> { + World world = dbRepository.getWorld(id); + int randomNumber; + do { + randomNumber = Utils.randomWorldNumber(); + } while (randomNumber == world.randomNumber); + world.randomNumber = randomNumber; + return world; + }).limit(queries) + .toList(); + dbRepository.updateWorlds(worlds); return ServerResponse.ok() - .contentType(MediaType.APPLICATION_JSON) + .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE) .body(worlds); } ServerResponse fortunes(ServerRequest request) { - var fortunes = dbRepository.fortunes(); + List fortunes = dbRepository.fortunes(); fortunes.add(new Fortune(0, "Additional fortune added at request time.")); - fortunes.sort(comparing(fortune -> fortune.message)); - return RenderingResponse - .create("fortunes") - .modelAttribute("fortunes", fortunes) + Collections.sort(fortunes); + return ServerResponse.ok() .header(HttpHeaders.CONTENT_TYPE, MediaType.TEXT_HTML_VALUE) - .build(); - } - - private static final int MIN_WORLD_NUMBER = 1; - private static final int MAX_WORLD_NUMBER_PLUS_ONE = 10_001; - - public static int randomWorldNumber() { - return ThreadLocalRandom.current().nextInt(MIN_WORLD_NUMBER, MAX_WORLD_NUMBER_PLUS_ONE); - } - - private static IntStream randomWorldNumbers() { - return ThreadLocalRandom.current().ints(MIN_WORLD_NUMBER, MAX_WORLD_NUMBER_PLUS_ONE) - // distinct() allows us to avoid using Hibernate's first-level cache in - // the JPA-based implementation. Using a cache like that would bypass - // querying the database, which would violate the test requirements. - .distinct(); + .body(JStachio.render(new Fortunes(fortunes))); } private static int parseQueryCount(String textValue) { diff --git a/frameworks/Java/spring/src/main/java/hello/web/Fortunes.java b/frameworks/Java/spring/src/main/java/hello/web/Fortunes.java new file mode 100644 index 00000000000..cbd6daf2396 --- /dev/null +++ b/frameworks/Java/spring/src/main/java/hello/web/Fortunes.java @@ -0,0 +1,10 @@ +package hello.web; + +import java.util.List; + +import hello.model.Fortune; +import io.jstach.jstache.JStache; + +@JStache(path = "fortunes.mustache") +public record Fortunes(List fortunes) { +} diff --git a/frameworks/Java/spring/src/main/resources/application.yml b/frameworks/Java/spring/src/main/resources/application.yml index 4f6592dc53b..efde83cda61 100644 --- a/frameworks/Java/spring/src/main/resources/application.yml +++ b/frameworks/Java/spring/src/main/resources/application.yml @@ -1,21 +1,21 @@ +server: + server-header: Spring + servlet: + encoding: + force: true --- spring: config: activate: on-profile: jdbc autoconfigure: - exclude: org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration,org.springframework.boot.autoconfigure.data.jpa.JpaRepositoriesAutoConfiguration,org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration,org.springframework.boot.autoconfigure.data.mongo.MongoDataAutoConfiguration,org.springframework.boot.autoconfigure.data.mongo.MongoRepositoriesAutoConfiguration,org.springframework.boot.autoconfigure.data.web.SpringDataWebAutoConfiguration - ---- -spring: - config: - activate: - on-profile: jdbc,jpa + exclude: org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration,org.springframework.boot.autoconfigure.data.mongo.MongoDataAutoConfiguration,org.springframework.boot.autoconfigure.data.mongo.MongoRepositoriesAutoConfiguration,org.springframework.boot.autoconfigure.data.web.SpringDataWebAutoConfiguration datasource: - url: jdbc:postgresql://${database.host}:${database.port}/${database.name} + url: jdbc:postgresql://${database.host}:${database.port}/${database.name}?loggerLevel=OFF&disableColumnSanitiser=true&assumeMinServerVersion=16&sslmode=disable username: ${database.username} password: ${database.password} - + hikari: + maximum-pool-size: 256 database: name: hello_world host: tfb-database @@ -23,23 +23,13 @@ database: username: benchmarkdbuser password: benchmarkdbpass ---- -spring: - config: - activate: - on-profile: jpa - autoconfigure: - exclude: org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration,org.springframework.boot.autoconfigure.data.mongo.MongoRepositoriesAutoConfiguration,org.springframework.boot.autoconfigure.data.mongo.MongoDataAutoConfiguration,org.springframework.boot.autoconfigure.data.web.SpringDataWebAutoConfiguration - jpa: - database-platform: org.hibernate.dialect.PostgreSQLDialect - --- spring: config: activate: on-profile: mongo autoconfigure: - exclude: org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration,org.springframework.boot.autoconfigure.data.jpa.JpaRepositoriesAutoConfiguration,org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration,org.springframework.boot.autoconfigure.data.web.SpringDataWebAutoConfiguration + exclude: org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration,org.springframework.boot.autoconfigure.data.web.SpringDataWebAutoConfiguration spring.data.mongodb: host: tfb-database @@ -50,7 +40,3 @@ spring.data.mongodb: spring: profiles: active: jdbc - -server.server-header: Spring -server.servlet.encoding.force: true -spring.jpa.open-in-view: false diff --git a/frameworks/Java/spring/src/main/resources/templates/fortunes.mustache b/frameworks/Java/spring/src/main/resources/fortunes.mustache similarity index 100% rename from frameworks/Java/spring/src/main/resources/templates/fortunes.mustache rename to frameworks/Java/spring/src/main/resources/fortunes.mustache From d96bcdc36e248a5ea0cb732909e3a601512b85f7 Mon Sep 17 00:00:00 2001 From: Jonathan Cooper <4676022+ReallySnazzy@users.noreply.github.com> Date: Tue, 1 Oct 2024 16:35:20 -0700 Subject: [PATCH 139/204] [OCaml/Dream] Add initial tests for Dream (#9278) --- frameworks/OCaml/dream/README.md | 35 ++++++++++++ frameworks/OCaml/dream/benchmark_config.json | 26 +++++++++ frameworks/OCaml/dream/dream.dockerfile | 12 +++++ frameworks/OCaml/dream/dream_test/bin/dune | 5 ++ frameworks/OCaml/dream/dream_test/bin/main.ml | 53 +++++++++++++++++++ .../OCaml/dream/dream_test/dream_test.opam | 35 ++++++++++++ .../OCaml/dream/dream_test/dune-project | 26 +++++++++ frameworks/OCaml/dream/dream_test/lib/dune | 2 + frameworks/OCaml/dream/dream_test/test/dune | 2 + .../dream/dream_test/test/test_dream_test.ml | 0 10 files changed, 196 insertions(+) create mode 100755 frameworks/OCaml/dream/README.md create mode 100755 frameworks/OCaml/dream/benchmark_config.json create mode 100644 frameworks/OCaml/dream/dream.dockerfile create mode 100755 frameworks/OCaml/dream/dream_test/bin/dune create mode 100755 frameworks/OCaml/dream/dream_test/bin/main.ml create mode 100644 frameworks/OCaml/dream/dream_test/dream_test.opam create mode 100755 frameworks/OCaml/dream/dream_test/dune-project create mode 100755 frameworks/OCaml/dream/dream_test/lib/dune create mode 100755 frameworks/OCaml/dream/dream_test/test/dune create mode 100755 frameworks/OCaml/dream/dream_test/test/test_dream_test.ml diff --git a/frameworks/OCaml/dream/README.md b/frameworks/OCaml/dream/README.md new file mode 100755 index 00000000000..86e484bc978 --- /dev/null +++ b/frameworks/OCaml/dream/README.md @@ -0,0 +1,35 @@ +# Dream + +## Overview + +Most of all of the code is inside of `test_dream/bin/main.ml` file. + +## Implemented tests + +| Test Name | Endpoint | +|------------|-------------------------------| +| Plain text | http://0.0.0.0:8080/plaintext | +| Json | http://0.0.0.0:8080/json | + +## Headers + +A simple middleware was added that adds the required headers for the Techempower Benchmarks. +The date header is refreshed only once per second as allowed by the rules for performance. + +## Dependencies + +The `test_dream/dune-project` and `test_dream/bin/dune` are where dependencies are managed +for this project. If you add a dependency to those locations and then run the following: + +``` +cd test_dream +dune build test_dream.opam +opam install --yes --deps-only . +``` + +You will update the opam package list and install your changes locally. + +## Running tests + +$ tfb --mode verify --test dream + diff --git a/frameworks/OCaml/dream/benchmark_config.json b/frameworks/OCaml/dream/benchmark_config.json new file mode 100755 index 00000000000..d5d83b838f4 --- /dev/null +++ b/frameworks/OCaml/dream/benchmark_config.json @@ -0,0 +1,26 @@ +{ + "framework": "dream", + "tests": [ + { + "default": { + "json_url": "/json", + "plaintext_url": "/plaintext", + "port": 8080, + "approach": "Realistic", + "classification": "Fullstack", + "database": "postgres", + "framework": "Dream", + "language": "OCaml", + "flavor": "None", + "orm": "Micro", + "platform": "http/af", + "webserver": "None", + "os": "Linux", + "database_os": "Linux", + "display_name": "Dream", + "notes": "", + "versus": "httpaf" + } + } + ] +} diff --git a/frameworks/OCaml/dream/dream.dockerfile b/frameworks/OCaml/dream/dream.dockerfile new file mode 100644 index 00000000000..8a806026a4e --- /dev/null +++ b/frameworks/OCaml/dream/dream.dockerfile @@ -0,0 +1,12 @@ +FROM ocaml/opam:debian-ocaml-5.1 +COPY ./dream_test/ /app +WORKDIR /app +USER root +RUN apt install -y libgmp-dev libev-dev pkg-config libssl-dev +RUN opam install --yes --deps-only . +RUN opam install dune +RUN eval $(opam env) +RUN opam exec -- dune build --profile release +CMD [ "./_build/default/bin/main.exe" ] +EXPOSE 8080 + diff --git a/frameworks/OCaml/dream/dream_test/bin/dune b/frameworks/OCaml/dream/dream_test/bin/dune new file mode 100755 index 00000000000..171e6829182 --- /dev/null +++ b/frameworks/OCaml/dream/dream_test/bin/dune @@ -0,0 +1,5 @@ +(executable + (public_name dream_test) + (name main) + (preprocess (pps lwt_ppx ppx_yojson_conv)) + (libraries dream_test dream ppx_yojson_conv calendar)) diff --git a/frameworks/OCaml/dream/dream_test/bin/main.ml b/frameworks/OCaml/dream/dream_test/bin/main.ml new file mode 100755 index 00000000000..4c5ac18c30c --- /dev/null +++ b/frameworks/OCaml/dream/dream_test/bin/main.ml @@ -0,0 +1,53 @@ +open Ppx_yojson_conv_lib.Yojson_conv.Primitives + +type message_object = { + message : string; +} [@@deriving yojson] + +let time_cache = Atomic.make false;; +let time_ref = ref("None");; + +let time () = + if not @@ Atomic.get time_cache + then begin + time_ref := CalendarLib.Printer.Calendar.sprint "%a, %d %b %Y %H:%M:%S UTC" @@ CalendarLib.Calendar.now (); + Atomic.set time_cache true; + (!time_ref) + end + else + (!time_ref);; + +let tech_empower_headers (inner_handler: Dream.handler) = + (fun (req) -> + let%lwt res = inner_handler req in + Dream.set_header res "Server" "dream"; + Dream.set_header res "Date" @@ time (); + Lwt.return res + );; + +let rec timer () = + Unix.sleepf 0.9; + Atomic.set time_cache false; + timer();; + +let () = + let time_invalidator = Domain.spawn(fun () -> timer ()) in + Dream.run ~interface: "0.0.0.0" + @@ tech_empower_headers + @@ Dream.router [ + Dream.get "/" (fun _ -> + Dream.html "Hello, world!" + ); + Dream.get "/plaintext" (fun _ -> + Dream.response ~headers: [("Content-Type", "text/plain")] + "Hello, world!" + |> Lwt.return + ); + Dream.get "/json" (fun _ -> + { message = "Hello, world!" } + |> yojson_of_message_object + |> Yojson.Safe.to_string + |> Dream.json + ); + ]; + Domain.join time_invalidator;; diff --git a/frameworks/OCaml/dream/dream_test/dream_test.opam b/frameworks/OCaml/dream/dream_test/dream_test.opam new file mode 100644 index 00000000000..b9db80a34bd --- /dev/null +++ b/frameworks/OCaml/dream/dream_test/dream_test.opam @@ -0,0 +1,35 @@ +# This file is generated by dune, edit dune-project instead +opam-version: "2.0" +synopsis: "A short synopsis" +description: "A longer description" +maintainer: ["Maintainer Name"] +authors: ["Author Name"] +license: "LICENSE" +tags: ["topics" "to describe" "your" "project"] +homepage: "https://github.com/username/reponame" +doc: "https://url/to/documentation" +bug-reports: "https://github.com/username/reponame/issues" +depends: [ + "ocaml" + "dune" {>= "3.14"} + "dream" + "lwt" + "ppx_yojson_conv" + "calendar" + "odoc" {with-doc} +] +build: [ + ["dune" "subst"] {dev} + [ + "dune" + "build" + "-p" + name + "-j" + jobs + "@install" + "@runtest" {with-test} + "@doc" {with-doc} + ] +] +dev-repo: "git+https://github.com/username/reponame.git" diff --git a/frameworks/OCaml/dream/dream_test/dune-project b/frameworks/OCaml/dream/dream_test/dune-project new file mode 100755 index 00000000000..aaeaf8c0df8 --- /dev/null +++ b/frameworks/OCaml/dream/dream_test/dune-project @@ -0,0 +1,26 @@ +(lang dune 3.14) + +(name dream_test) + +(generate_opam_files true) + +(source + (github username/reponame)) + +(authors "Author Name") + +(maintainers "Maintainer Name") + +(license LICENSE) + +(documentation https://url/to/documentation) + +(package + (name dream_test) + (synopsis "A short synopsis") + (description "A longer description") + (depends ocaml dune dream lwt ppx_yojson_conv calendar) + (tags + (topics "to describe" your project))) + +; See the complete stanza docs at https://dune.readthedocs.io/en/stable/dune-files.html#dune-project diff --git a/frameworks/OCaml/dream/dream_test/lib/dune b/frameworks/OCaml/dream/dream_test/lib/dune new file mode 100755 index 00000000000..b8d991f91da --- /dev/null +++ b/frameworks/OCaml/dream/dream_test/lib/dune @@ -0,0 +1,2 @@ +(library + (name dream_test)) diff --git a/frameworks/OCaml/dream/dream_test/test/dune b/frameworks/OCaml/dream/dream_test/test/dune new file mode 100755 index 00000000000..434f4a8ee36 --- /dev/null +++ b/frameworks/OCaml/dream/dream_test/test/dune @@ -0,0 +1,2 @@ +(test + (name test_dream_test)) diff --git a/frameworks/OCaml/dream/dream_test/test/test_dream_test.ml b/frameworks/OCaml/dream/dream_test/test/test_dream_test.ml new file mode 100755 index 00000000000..e69de29bb2d From 289d579cafb5859107dca2f71648148af2ab0f9a Mon Sep 17 00:00:00 2001 From: Redkale Date: Wed, 2 Oct 2024 07:35:54 +0800 Subject: [PATCH 140/204] Update redkale-block (#9295) * Update redkale-block * ConvertStandardString --- frameworks/Java/redkale/BenchmarkService.java | 7 +------ frameworks/Java/redkale/benchmark_config.json | 1 + frameworks/Java/redkale/conf/application.xml | 2 +- frameworks/Java/redkale/config.toml | 1 + frameworks/Java/redkale/redkale-block.dockerfile | 1 + .../java/org/redkalex/benchmark/BenchmarkService.java | 8 +------- .../src/main/java/org/redkalex/benchmark/Message.java | 4 ++-- 7 files changed, 8 insertions(+), 16 deletions(-) diff --git a/frameworks/Java/redkale/BenchmarkService.java b/frameworks/Java/redkale/BenchmarkService.java index 39e9956a75d..558cbe2fbb2 100644 --- a/frameworks/Java/redkale/BenchmarkService.java +++ b/frameworks/Java/redkale/BenchmarkService.java @@ -6,13 +6,12 @@ package org.redkalex.benchmark; import java.util.*; -import java.util.concurrent.*; +import java.util.concurrent.ThreadLocalRandom; import java.util.stream.Stream; import org.redkale.annotation.*; import org.redkale.net.http.*; import org.redkale.service.AbstractService; import org.redkale.source.DataSource; -import org.redkale.util.AnyValue; /** * 测试redkale-jdbc, 需要覆盖到原BenchmarkService @@ -27,10 +26,6 @@ public class BenchmarkService extends AbstractService { @Resource private DataSource source; - public void init(AnyValue conf) { - source.finds(CachedWorld.class, 1); - } - @NonBlocking @RestMapping(auth = false) public byte[] plaintext() { diff --git a/frameworks/Java/redkale/benchmark_config.json b/frameworks/Java/redkale/benchmark_config.json index fa84965daa3..2371e0e2bec 100644 --- a/frameworks/Java/redkale/benchmark_config.json +++ b/frameworks/Java/redkale/benchmark_config.json @@ -96,6 +96,7 @@ "versus": "Redkale" }, "block": { + "plaintext_url": "/plaintext", "db_url": "/db", "query_url": "/queries?q=", "fortune_url": "/fortunes", diff --git a/frameworks/Java/redkale/conf/application.xml b/frameworks/Java/redkale/conf/application.xml index aa535805113..642b3da5928 100644 --- a/frameworks/Java/redkale/conf/application.xml +++ b/frameworks/Java/redkale/conf/application.xml @@ -8,7 +8,7 @@ - + diff --git a/frameworks/Java/redkale/config.toml b/frameworks/Java/redkale/config.toml index c2fcbb80d77..96d8a7f4bf8 100644 --- a/frameworks/Java/redkale/config.toml +++ b/frameworks/Java/redkale/config.toml @@ -71,6 +71,7 @@ webserver = "Redkale" versus = "Redkale" [block] +urls.plaintext = "/plaintext" urls.db = "/db" urls.fortune = "/fortunes" urls.query = "/queries?q=" diff --git a/frameworks/Java/redkale/redkale-block.dockerfile b/frameworks/Java/redkale/redkale-block.dockerfile index b163c60e53f..55e13c76b73 100644 --- a/frameworks/Java/redkale/redkale-block.dockerfile +++ b/frameworks/Java/redkale/redkale-block.dockerfile @@ -9,6 +9,7 @@ RUN mvn package -q FROM openjdk:23-jdk-slim WORKDIR /redkale COPY conf conf +RUN sed -i 's/sameHeader="true"/ /g' /redkale/conf/application.xml COPY --from=maven /redkale/target/redkale-benchmark-1.0.0.jar redkale-benchmark.jar EXPOSE 8080 diff --git a/frameworks/Java/redkale/src/main/java/org/redkalex/benchmark/BenchmarkService.java b/frameworks/Java/redkale/src/main/java/org/redkalex/benchmark/BenchmarkService.java index 48af592f928..e2ebc7b8aad 100644 --- a/frameworks/Java/redkale/src/main/java/org/redkalex/benchmark/BenchmarkService.java +++ b/frameworks/Java/redkale/src/main/java/org/redkalex/benchmark/BenchmarkService.java @@ -7,13 +7,11 @@ import java.util.*; import java.util.concurrent.*; -import java.util.stream.IntStream; -import java.util.stream.Stream; +import java.util.stream.*; import org.redkale.annotation.*; import org.redkale.net.http.*; import org.redkale.service.AbstractService; import org.redkale.source.DataSource; -import org.redkale.util.AnyValue; /** * @@ -28,10 +26,6 @@ public class BenchmarkService extends AbstractService { @Resource private DataSource source; - public void init(AnyValue conf) { - source.finds(CachedWorld.class, 1); - } - @RestMapping(auth = false) public byte[] plaintext() { return helloBytes; diff --git a/frameworks/Java/redkale/src/main/java/org/redkalex/benchmark/Message.java b/frameworks/Java/redkale/src/main/java/org/redkalex/benchmark/Message.java index 00c529e9eee..a5e7aed358d 100644 --- a/frameworks/Java/redkale/src/main/java/org/redkalex/benchmark/Message.java +++ b/frameworks/Java/redkale/src/main/java/org/redkalex/benchmark/Message.java @@ -6,7 +6,7 @@ package org.redkalex.benchmark; import org.redkale.annotation.Serial; -import org.redkale.convert.ConvertSmallString; +import org.redkale.convert.ConvertStandardString; import org.redkale.convert.json.JsonConvert; /** @@ -16,7 +16,7 @@ @Serial public final class Message { - @ConvertSmallString + @ConvertStandardString private String message; public Message() {} From 27cade8f3987e48fa3505d879ee1994c2f8b32d9 Mon Sep 17 00:00:00 2001 From: SaltyAom Date: Wed, 2 Oct 2024 06:36:09 +0700 Subject: [PATCH 141/204] [Elysia] fix /plaintext failing on newer Bun version (#9290) * fix(elysia): native static response not setting headers conflict with recent Bun version * fix(elysia): remove lockfile * fix(elysia): update lockfile * fix(elysia): update elysia version * fix(elysia): update lockfile --- frameworks/TypeScript/elysia/bun.lockb | Bin 3513 -> 3513 bytes frameworks/TypeScript/elysia/package.json | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/frameworks/TypeScript/elysia/bun.lockb b/frameworks/TypeScript/elysia/bun.lockb index 0020cf63f06be5b698becc47ddfdaa4336096013..5d4cdb0b97af1c97b83aa10bf44cc1db342ee378 100755 GIT binary patch delta 492 zcmdlfy;FLEp2BDLxQ6$S8|PZCudFP6c7D24_zNK?wv6hWkB3+Da3r3Y=;x&{m4Sgl zl7XS21xO15>2e^=3#60t^RqKk85kz+P*4zX?pSl?@FEfUxl9jCgtk2Azd!r2VP8V| zd1)u&dKIK_oe(em;=EsGZ7s9uA zOgpN!W_f?Ig>ve4V`+{zr@5a7f4-D_YwEgQMg|5(hJXD3fHd>umn`9vU$F2_Udrmt z$U1oje7|kZ{=9HfN zfm6y97G|(;VPcFkG}1HFGiHE=DlFuf7!CA{jr5F77^Y6<=91iO$K}H)WTsb=UX@>v znwMCRsasN6kXk&spId9P61VhZ6`rWcn|RbGC-X>8e#q@SxsFG2@=YE`b~8OAkfzCk G>@xs9GqD8# delta 490 zcmdlfy;FLEp2Dr}j0cti2jnY#70S<@wUYhy!=#8|`@k%#Msc)jV^%v$JMjI+AGpmq~uc$KL%?yI-F6T~^SrLC8U<@W+oz6R+n9t?FBo z8S?E*H?tjoyq>&pn;l3c^hp85kHD{_+0<(#(?`S;Hs4VBwuSm&F@s$4nq^ z1}pF6uPola>_A_@0E^MBZQl+xGq~};U7760?Qb>Zz2&zLu9-nEFJC;*aaZ`k7WcN- z@gJw061-G-?6^VDS(fdb3cqXT#TQ9Wxp|$v{pVx>_WsRh*xoTQ8cp8KDa}|unVU<} z6c%8xKw)BxGte{BGhkqV1t~1pfHH=926~1J3=1cJ Date: Wed, 2 Oct 2024 00:36:21 +0100 Subject: [PATCH 142/204] Resolve Axum 0.7 regressions (#9291) * perf: restore axum [postgresql] performance * fix: axum plaintext regression * feat: upgrade to axum 0.7.6 --- frameworks/Rust/axum/Cargo.lock | 21 +++++++++++-------- frameworks/Rust/axum/Cargo.toml | 2 +- frameworks/Rust/axum/src/main.rs | 6 ++++-- frameworks/Rust/axum/src/main_mongo.rs | 22 +++----------------- frameworks/Rust/axum/src/main_mongo_raw.rs | 19 ++--------------- frameworks/Rust/axum/src/main_pg.rs | 6 ++++-- frameworks/Rust/axum/src/server.rs | 24 ++++++++++++++++++++++ 7 files changed, 50 insertions(+), 50 deletions(-) diff --git a/frameworks/Rust/axum/Cargo.lock b/frameworks/Rust/axum/Cargo.lock index 005a10fb7ca..8f756182439 100644 --- a/frameworks/Rust/axum/Cargo.lock +++ b/frameworks/Rust/axum/Cargo.lock @@ -121,9 +121,9 @@ checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" [[package]] name = "axum" -version = "0.7.5" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a6c9af12842a67734c9a2e355436e5d03b22383ed60cf13cd0c18fbfe3dcbcf" +checksum = "8f43644eed690f5374f1af436ecd6aea01cd201f6fbdf0178adaf6907afb2cec" dependencies = [ "async-trait", "axum-core", @@ -147,16 +147,16 @@ dependencies = [ "serde_urlencoded", "sync_wrapper 1.0.1", "tokio", - "tower 0.4.13", + "tower 0.5.1", "tower-layer", "tower-service", ] [[package]] name = "axum-core" -version = "0.4.3" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a15c63fd72d41492dc4f497196f5da1fb04fb7529e631d73630d1b491e47a2e3" +checksum = "5e6b8ba012a258d63c9adfa28b9ddcf66149da6f986c5b5452e629d5ee64bf00" dependencies = [ "async-trait", "bytes", @@ -167,7 +167,7 @@ dependencies = [ "mime", "pin-project-lite", "rustversion", - "sync_wrapper 0.1.2", + "sync_wrapper 1.0.1", "tower-layer", "tower-service", ] @@ -201,7 +201,7 @@ dependencies = [ "tokio-pg-mapper", "tokio-pg-mapper-derive", "tokio-postgres", - "tower 0.5.0", + "tower 0.5.1", "tower-http", "yarte", ] @@ -1056,6 +1056,8 @@ dependencies = [ "hyper", "pin-project-lite", "tokio", + "tower 0.4.13", + "tower-service", ] [[package]] @@ -2779,14 +2781,15 @@ dependencies = [ [[package]] name = "tower" -version = "0.5.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36b837f86b25d7c0d7988f00a54e74739be6477f2aac6201b8f429a7569991b7" +checksum = "2873938d487c3cfb9aed7546dc9f2711d867c9f90c46b889989a2cb84eba6b4f" dependencies = [ "futures-core", "futures-util", "pin-project-lite", "sync_wrapper 0.1.2", + "tokio", "tower-layer", "tower-service", ] diff --git a/frameworks/Rust/axum/Cargo.toml b/frameworks/Rust/axum/Cargo.toml index 49b594972d1..a47514726c7 100644 --- a/frameworks/Rust/axum/Cargo.toml +++ b/frameworks/Rust/axum/Cargo.toml @@ -39,7 +39,7 @@ simd-json = [ ] [dependencies] -axum = { version = "0.7.5", default-features = false, features = [ +axum = { version = "0.7.6", default-features = false, features = [ "json", "query", "http1", diff --git a/frameworks/Rust/axum/src/main.rs b/frameworks/Rust/axum/src/main.rs index b29da958d20..70858e27ddc 100644 --- a/frameworks/Rust/axum/src/main.rs +++ b/frameworks/Rust/axum/src/main.rs @@ -11,11 +11,13 @@ use axum::Json; use common::simd_json::Json; /// Return a plaintext static string. -pub async fn plaintext() -> impl IntoResponse { - (StatusCode::OK, "Hello, World!") +#[inline(always)] +pub async fn plaintext() -> &'static str { + "Hello, World!" } /// Return a JSON message. +#[inline(always)] pub async fn json() -> impl IntoResponse { let message = Message { message: "Hello, World!", diff --git a/frameworks/Rust/axum/src/main_mongo.rs b/frameworks/Rust/axum/src/main_mongo.rs index 8f7ac7961c3..6d301189b9a 100644 --- a/frameworks/Rust/axum/src/main_mongo.rs +++ b/frameworks/Rust/axum/src/main_mongo.rs @@ -1,5 +1,6 @@ mod common; mod mongo; +mod server; //mod mongo_raw; use std::time::Duration; @@ -24,8 +25,6 @@ use mongodb::{ use rand::{rngs::SmallRng, thread_rng, Rng, SeedableRng}; use yarte::Template; -mod server; - use common::{ get_env, utils::{parse_params, Params, Utf8Html}, @@ -117,25 +116,10 @@ async fn fortunes(DatabaseConnection(db): DatabaseConnection) -> impl IntoRespon fn main() { dotenv().ok(); - - let rt = tokio::runtime::Builder::new_current_thread() - .enable_all() - .build() - .unwrap(); - - for _ in 1..num_cpus::get() { - std::thread::spawn(move || { - let rt = tokio::runtime::Builder::new_current_thread() - .enable_all() - .build() - .unwrap(); - rt.block_on(serve()); - }); - } - rt.block_on(serve()); + server::start_tokio(serve_app) } -async fn serve() { +async fn serve_app() { let database_url: String = get_env("MONGODB_URL"); let max_pool_size: u32 = get_env("MONGODB_MAX_POOL_SIZE"); let min_pool_size: u32 = get_env("MONGODB_MIN_POOL_SIZE"); diff --git a/frameworks/Rust/axum/src/main_mongo_raw.rs b/frameworks/Rust/axum/src/main_mongo_raw.rs index fdf09c179a3..0d2735ad3bb 100644 --- a/frameworks/Rust/axum/src/main_mongo_raw.rs +++ b/frameworks/Rust/axum/src/main_mongo_raw.rs @@ -86,25 +86,10 @@ async fn updates( fn main() { dotenv().ok(); - - let rt = tokio::runtime::Builder::new_current_thread() - .enable_all() - .build() - .unwrap(); - - for _ in 1..num_cpus::get() { - std::thread::spawn(move || { - let rt = tokio::runtime::Builder::new_current_thread() - .enable_all() - .build() - .unwrap(); - rt.block_on(serve()); - }); - } - rt.block_on(serve()); + server::start_tokio(serve_app) } -async fn serve() { +async fn serve_app() { let database_url: String = get_env("MONGODB_URL"); let max_pool_size: u32 = get_env("MONGODB_MAX_POOL_SIZE"); let min_pool_size: u32 = get_env("MONGODB_MIN_POOL_SIZE"); diff --git a/frameworks/Rust/axum/src/main_pg.rs b/frameworks/Rust/axum/src/main_pg.rs index 20acb2a1769..be691f9720c 100644 --- a/frameworks/Rust/axum/src/main_pg.rs +++ b/frameworks/Rust/axum/src/main_pg.rs @@ -78,10 +78,12 @@ async fn updates( (StatusCode::OK, Json(worlds)) } -#[tokio::main] -async fn main() { +fn main() { dotenv().ok(); + server::start_tokio(serve_app) +} +async fn serve_app() { let database_url: String = get_env("POSTGRES_URL"); // Create shared database connection diff --git a/frameworks/Rust/axum/src/server.rs b/frameworks/Rust/axum/src/server.rs index 5e03a6aca88..6d861277c10 100644 --- a/frameworks/Rust/axum/src/server.rs +++ b/frameworks/Rust/axum/src/server.rs @@ -1,4 +1,5 @@ use std::{ + future::Future, io, net::{Ipv4Addr, SocketAddr, TcpListener}, }; @@ -104,3 +105,26 @@ pub async fn serve_hyper(app: Router<()>, port: Option) { }); } } + +/// Start a single-threaded tokio runtime on multiple threads. +#[allow(dead_code)] +pub fn start_tokio(f: fn() -> Fut) +where + Fut: Future + 'static, +{ + let rt = tokio::runtime::Builder::new_current_thread() + .enable_all() + .build() + .unwrap(); + + for _ in 1..num_cpus::get() { + std::thread::spawn(move || { + let rt = tokio::runtime::Builder::new_current_thread() + .enable_all() + .build() + .unwrap(); + rt.block_on(f()); + }); + } + rt.block_on(f()); +} From 19dbe27e1d62887e261840d04f4f43fa5550bd32 Mon Sep 17 00:00:00 2001 From: Dragos Varovici Date: Tue, 1 Oct 2024 17:36:43 -0600 Subject: [PATCH 143/204] Zap performance improvements (#9293) --- frameworks/Zig/zap/build-nginx-conf.sh | 13 +++++++++ frameworks/Zig/zap/build.zig | 19 ------------ frameworks/Zig/zap/build.zig.zon | 1 - frameworks/Zig/zap/nginx.conf | 33 +++++++++++++++++++++ frameworks/Zig/zap/run.sh | 3 -- frameworks/Zig/zap/src/endpoints.zig | 24 ++++++++++------ frameworks/Zig/zap/src/main.zig | 30 +++++++++++++++---- frameworks/Zig/zap/src/pool.zig | 4 +-- frameworks/Zig/zap/start-servers.sh | 10 +++++++ frameworks/Zig/zap/zap.dockerfile | 40 ++++++++------------------ 10 files changed, 110 insertions(+), 67 deletions(-) create mode 100644 frameworks/Zig/zap/build-nginx-conf.sh create mode 100644 frameworks/Zig/zap/nginx.conf delete mode 100644 frameworks/Zig/zap/run.sh create mode 100644 frameworks/Zig/zap/start-servers.sh diff --git a/frameworks/Zig/zap/build-nginx-conf.sh b/frameworks/Zig/zap/build-nginx-conf.sh new file mode 100644 index 00000000000..ecb55c80bfa --- /dev/null +++ b/frameworks/Zig/zap/build-nginx-conf.sh @@ -0,0 +1,13 @@ +#!/bin/bash + +CPU_COUNT=$(nproc) +P=3000 +END=$(($P+$CPU_COUNT)) +CONF="" + +while [ $P -lt $END ]; do + CONF+="\t\tserver 127.0.0.1:$P;\n" + let P=P+1 +done + +sed -i "s|# replace|$CONF|g" nginx.conf diff --git a/frameworks/Zig/zap/build.zig b/frameworks/Zig/zap/build.zig index 762284c2acb..2da55a07981 100644 --- a/frameworks/Zig/zap/build.zig +++ b/frameworks/Zig/zap/build.zig @@ -40,16 +40,13 @@ pub fn build(b: *std.Build) !void { const zap_module = b.dependency("zap", dep_opts).module("zap"); const pg_module = b.dependency("pg", dep_opts).module("pg"); - const dig_module = b.dependency("dig", dep_opts).module("dns"); try modules.put("zap", zap_module); try modules.put("pg", pg_module); - try modules.put("dig", dig_module); // // Expose this as a module that others can import exe.root_module.addImport("zap", zap_module); exe.root_module.addImport("pg", pg_module); - exe.root_module.addImport("dig", dig_module); exe.linkLibrary(zap.artifact("facil.io")); @@ -80,20 +77,4 @@ pub fn build(b: *std.Build) !void { // This will evaluate the `run` step rather than the default, which is "install". const run_step = b.step("run", "Run the app"); run_step.dependOn(&run_cmd.step); - - // Creates a step for unit testing. This only builds the test executable - // but does not run it. - const unit_tests = b.addTest(.{ - .root_source_file = b.path("src/main.zig"), - .target = target, - .optimize = optimize, - }); - - const run_unit_tests = b.addRunArtifact(unit_tests); - - // Similar to creating the run step earlier, this exposes a `test` step to - // the `zig build --help` menu, providing a way for the user to request - // running the unit tests. - const test_step = b.step("test", "Run unit tests"); - test_step.dependOn(&run_unit_tests.step); } diff --git a/frameworks/Zig/zap/build.zig.zon b/frameworks/Zig/zap/build.zig.zon index 871e73b7f76..3f492b7d954 100644 --- a/frameworks/Zig/zap/build.zig.zon +++ b/frameworks/Zig/zap/build.zig.zon @@ -9,5 +9,4 @@ }, .pg = .{ .url = "https://github.com/karlseguin/pg.zig/archive/239a4468163a49d8c0d03285632eabe96003e9e2.tar.gz", .hash = "1220a1d7e51e2fa45e547c76a9e099c09d06e14b0b9bfc6baa89367f56f1ded399a0" }, - .dig = .{ .url = "https://github.com/lun-4/zigdig/archive/a54c85c26aa83c64ee81e3ee1818890be5cbed0b.tar.gz", .hash = "1220f078ab62d1328339504f9122dc4d241be30ada451628d78b8a3bf5bb9be1dcba" }, } } diff --git a/frameworks/Zig/zap/nginx.conf b/frameworks/Zig/zap/nginx.conf new file mode 100644 index 00000000000..f394b2ad206 --- /dev/null +++ b/frameworks/Zig/zap/nginx.conf @@ -0,0 +1,33 @@ +error_log stderr; +worker_processes auto; + +events { + worker_connections 65535; + multi_accept off; +} + +http { + default_type application/octet-stream; + client_body_temp_path /tmp; + access_log off; + + sendfile on; + tcp_nopush on; + keepalive_requests 100000; + keepalive_timeout 65; + + upstream workers { + # replace + } + + server { + listen 8080; + server_name tfb-server; + + location / { + proxy_http_version 1.1; + proxy_set_header Connection ""; + proxy_pass http://workers; + } + } +} diff --git a/frameworks/Zig/zap/run.sh b/frameworks/Zig/zap/run.sh deleted file mode 100644 index b4698a15de1..00000000000 --- a/frameworks/Zig/zap/run.sh +++ /dev/null @@ -1,3 +0,0 @@ -echo "Waiting for ZAP framework to start..." - -zap \ No newline at end of file diff --git a/frameworks/Zig/zap/src/endpoints.zig b/frameworks/Zig/zap/src/endpoints.zig index 3492e686591..44a3afc43e2 100644 --- a/frameworks/Zig/zap/src/endpoints.zig +++ b/frameworks/Zig/zap/src/endpoints.zig @@ -168,20 +168,28 @@ pub const DbEndpoint = struct { } } - // std.debug.print("Attempting to return random: {}\n", .{random_number}); - if (random_number == 0) { return; } - var conn = pool.acquire() catch return; - defer conn.release(); - - const row_result = conn.row("SELECT id, randomNumber FROM World WHERE id = $1", .{random_number}) catch |err| { + const json_to_send = getJson(pool, random_number) catch |err| { std.debug.print("Error querying database: {}\n", .{err}); return; }; + + req.sendBody(json_to_send) catch return; + + return; + } + + fn getJson(pool: *pg.Pool, random_number: u32) ![]const u8{ + var conn = try pool.acquire(); + defer conn.release(); + + const row_result = try conn.row("SELECT id, randomNumber FROM World WHERE id = $1", .{random_number}); + var row = row_result.?; + defer row.deinit() catch {}; const world = World{ .id = row.get(i32, 0), .randomNumber = row.get(i32, 1) }; @@ -193,9 +201,7 @@ pub const DbEndpoint = struct { json_to_send = "null"; } - req.sendBody(json_to_send) catch return; - - return; + return json_to_send; } }; diff --git a/frameworks/Zig/zap/src/main.zig b/frameworks/Zig/zap/src/main.zig index 0c66a7639bb..e2792726f04 100644 --- a/frameworks/Zig/zap/src/main.zig +++ b/frameworks/Zig/zap/src/main.zig @@ -1,8 +1,8 @@ const std = @import("std"); +const builtin = @import("builtin"); const zap = @import("zap"); const pg = @import("pg"); const regex = @import("regex"); -const dns = @import("dns"); const pool = @import("pool.zig"); const endpoints = @import("endpoints.zig"); @@ -23,6 +23,24 @@ pub fn main() !void { const allocator = tsa.allocator(); + var zap_port: []u8 = undefined; + var arg_string = try std.fmt.allocPrint(allocator, "{s}", .{"0"}); + defer allocator.free(arg_string); + + var args = try std.process.argsWithAllocator(allocator); + defer args.deinit(); + while (args.next()) |arg| { + arg_string = try std.fmt.allocPrint(allocator, "{s}", .{arg}); + + zap_port = arg_string; // use arg + } + + var port = try std.fmt.parseInt(u16, zap_port, 0); + + if (port == 0) { + port = 3000; + } + var pg_pool = try pool.initPool(allocator); defer pg_pool.deinit(); @@ -68,7 +86,7 @@ pub fn main() !void { var listener = try zap.Middleware.Listener(middleware.Context).init( .{ .on_request = null, // must be null - .port = 3000, + .port = port, .log = false, .max_clients = 100000, }, @@ -78,13 +96,15 @@ pub fn main() !void { ); try listener.listen(); - const cpuCount = @as(i16, @intCast(std.Thread.getCpuCount() catch 1)); + //const cpuCount = @as(i16, @intCast(std.Thread.getCpuCount() catch 1)); + //const workers = if (builtin.mode == .Debug) 1 else cpuCount; + const threads = 128; - std.debug.print("Listening on 0.0.0.0:3000 on {d} threads\n", .{cpuCount}); + std.debug.print("Listening at 0.0.0.0:{d} on {d} threads\n", .{port, threads}); // start worker threads zap.start(.{ - .threads = 16 * cpuCount, + .threads = threads, .workers = 1, }); } diff --git a/frameworks/Zig/zap/src/pool.zig b/frameworks/Zig/zap/src/pool.zig index 84df32104b0..6615ae217ce 100644 --- a/frameworks/Zig/zap/src/pool.zig +++ b/frameworks/Zig/zap/src/pool.zig @@ -10,7 +10,7 @@ const Regex = regex.Regex; pub fn initPool(allocator: Allocator) !*pg.Pool { const info = try parsePostgresConnStr(allocator); - std.debug.print("Connection: {s}:{s}@{s}:{d}/{s}\n", .{ info.username, info.password, info.hostname, info.port, info.database }); + //std.debug.print("Connection: {s}:{s}@{s}:{d}/{s}\n", .{ info.username, info.password, info.hostname, info.port, info.database }); const pg_pool = try Pool.init(allocator, .{ .size = 28, @@ -60,7 +60,7 @@ fn addressAsString(address: std.net.Address) ![]const u8 { fn parsePostgresConnStr(allocator: Allocator) !ConnectionInfo { const pg_port = try getEnvVar(allocator, "PG_PORT", "5432"); - std.debug.print("tfb port {s}\n", .{pg_port}); + // std.debug.print("tfb port {s}\n", .{pg_port}); var port = try std.fmt.parseInt(u16, pg_port, 0); if (port == 0) { diff --git a/frameworks/Zig/zap/start-servers.sh b/frameworks/Zig/zap/start-servers.sh new file mode 100644 index 00000000000..b5cf175de41 --- /dev/null +++ b/frameworks/Zig/zap/start-servers.sh @@ -0,0 +1,10 @@ +#!/bin/bash + +CPU_COUNT=$(nproc) +P=3000 +END=$(($P+$CPU_COUNT)) + +while [ $P -lt $END ]; do + zap $P & + let P=P+1 +done diff --git a/frameworks/Zig/zap/zap.dockerfile b/frameworks/Zig/zap/zap.dockerfile index 9aa8a4109ae..71123f4f3e7 100644 --- a/frameworks/Zig/zap/zap.dockerfile +++ b/frameworks/Zig/zap/zap.dockerfile @@ -9,38 +9,22 @@ ENV PG_HOST=tfb-database ENV PG_PORT=5432 COPY src src -COPY run.sh run.sh - COPY build.zig.zon build.zig.zon COPY build.zig build.zig +COPY start-servers.sh start-servers.sh +COPY build-nginx-conf.sh build-nginx-conf.sh +COPY nginx.conf nginx.conf -RUN dnf install -y zig -RUN zig version -# RUN zig build -Doptimize=ReleaseFast -RUN zig build -RUN cp /zap/zig-out/bin/zap /usr/local/bin - -EXPOSE 3000 - -CMD ["sh", "run.sh"] - -# FROM alpine:3.19 +RUN chmod +x start-servers.sh +RUN chmod +x build-nginx-conf.sh -# WORKDIR /zap +RUN ./build-nginx-conf.sh -# ENV PG_USER=benchmarkdbuser -# ENV PG_PASS=benchmarkdbpass -# ENV PG_DB=hello_world -# ENV PG_HOST=tfb-database -# ENV PG_PORT=5432 - -# RUN apk update -# RUN apk add libc6-compat - -# COPY run.sh run.sh - -# COPY --from=build /zap/zig-out/bin/zap /usr/local/bin +RUN dnf install -y zig nginx +RUN zig version +RUN zig build -Doptimize=ReleaseFast +RUN cp /zap/zig-out/bin/zap /usr/local/bin -# EXPOSE 3000 +EXPOSE 8080 -# CMD ["sh", "run.sh"] \ No newline at end of file +CMD ./start-servers.sh && nginx -c /zap/nginx.conf -g "daemon off;" \ No newline at end of file From 85ff4916681461ffe36724a91895cbc978fcf20b Mon Sep 17 00:00:00 2001 From: Joan Miquel Date: Wed, 2 Oct 2024 01:37:03 +0200 Subject: [PATCH 144/204] [toolset] Postgresql update to v17 (#9296) --- toolset/databases/postgres/postgres.dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/toolset/databases/postgres/postgres.dockerfile b/toolset/databases/postgres/postgres.dockerfile index 757d3ba79e8..aa2bcebf01d 100644 --- a/toolset/databases/postgres/postgres.dockerfile +++ b/toolset/databases/postgres/postgres.dockerfile @@ -1,4 +1,4 @@ -FROM postgres:16-bookworm +FROM postgres:17-bookworm ENV PGDATA=/ssd/postgresql \ POSTGRES_DB=hello_world \ From 71b06236af804042873677a66d8f4a1b43fc2dde Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 9 Oct 2024 01:34:27 +0000 Subject: [PATCH 145/204] Bump System.Runtime.Caching Bumps [System.Runtime.Caching](https://github.com/dotnet/runtime) from 8.0.0 to 8.0.1. - [Release notes](https://github.com/dotnet/runtime/releases) - [Commits](https://github.com/dotnet/runtime/compare/v8.0.0...v8.0.1) --- updated-dependencies: - dependency-name: System.Runtime.Caching dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- .../CSharp/beetlex/PlatformBenchmarks/PlatformBenchmarks.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frameworks/CSharp/beetlex/PlatformBenchmarks/PlatformBenchmarks.csproj b/frameworks/CSharp/beetlex/PlatformBenchmarks/PlatformBenchmarks.csproj index ba5b9d4202d..d6a786daa3b 100644 --- a/frameworks/CSharp/beetlex/PlatformBenchmarks/PlatformBenchmarks.csproj +++ b/frameworks/CSharp/beetlex/PlatformBenchmarks/PlatformBenchmarks.csproj @@ -12,7 +12,7 @@ - + From 8d4f5ed1edf0204493a62252b1d097f8dcb5271c Mon Sep 17 00:00:00 2001 From: fakeshadow <24548779@qq.com> Date: Fri, 11 Oct 2024 00:46:02 +0800 Subject: [PATCH 146/204] [xitca-web] add bench for async orm (#9287) * [xitca-web] add bench for async orm * dep fix * use release build of xitca-postgres * fix framework naming * dep update * fix build * add unrealistic db impl * dedup * improve compile time * update to pre-release version of xitca-web --- frameworks/Rust/xitca-web/Cargo.lock | 576 +++++++++--------- frameworks/Rust/xitca-web/Cargo.toml | 61 +- .../Rust/xitca-web/benchmark_config.json | 18 +- frameworks/Rust/xitca-web/src/db.rs | 143 ++--- .../Rust/xitca-web/src/db_diesel_async.rs | 153 +++++ .../Rust/xitca-web/src/db_unrealistic.rs | 130 ++++ frameworks/Rust/xitca-web/src/db_util.rs | 53 ++ frameworks/Rust/xitca-web/src/main.rs | 16 +- frameworks/Rust/xitca-web/src/main_axum.rs | 150 ----- frameworks/Rust/xitca-web/src/main_iou.rs | 162 +++-- frameworks/Rust/xitca-web/src/main_orm.rs | 67 ++ frameworks/Rust/xitca-web/src/ser.rs | 41 +- frameworks/Rust/xitca-web/src/util.rs | 40 +- .../Rust/xitca-web/xitca-web-axum.dockerfile | 10 - .../Rust/xitca-web/xitca-web-orm.dockerfile | 10 + 15 files changed, 945 insertions(+), 685 deletions(-) create mode 100644 frameworks/Rust/xitca-web/src/db_diesel_async.rs create mode 100644 frameworks/Rust/xitca-web/src/db_unrealistic.rs create mode 100644 frameworks/Rust/xitca-web/src/db_util.rs delete mode 100644 frameworks/Rust/xitca-web/src/main_axum.rs create mode 100644 frameworks/Rust/xitca-web/src/main_orm.rs delete mode 100644 frameworks/Rust/xitca-web/xitca-web-axum.dockerfile create mode 100644 frameworks/Rust/xitca-web/xitca-web-orm.dockerfile diff --git a/frameworks/Rust/xitca-web/Cargo.lock b/frameworks/Rust/xitca-web/Cargo.lock index 14daebadc05..71038073ca5 100644 --- a/frameworks/Rust/xitca-web/Cargo.lock +++ b/frameworks/Rust/xitca-web/Cargo.lock @@ -1,12 +1,12 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 [[package]] name = "addr2line" -version = "0.24.1" +version = "0.24.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5fb1d8e4442bd405fdfd1dacb42792696b0cf9cb15882e5d097b742a676d375" +checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" dependencies = [ "gimli", ] @@ -19,9 +19,9 @@ checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" [[package]] name = "async-trait" -version = "0.1.82" +version = "0.1.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a27b8a3a6e1a44fa4c8baf1f653e4172e81486d4941f2237e20dc2d0cf4ddff1" +checksum = "721cae7de5c34fbb2acd27e21e6d2cf7b886dce0c27388d46c4e6c47ea4318dd" dependencies = [ "proc-macro2", "quote", @@ -39,59 +39,9 @@ dependencies = [ [[package]] name = "autocfg" -version = "1.3.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" - -[[package]] -name = "axum" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a6c9af12842a67734c9a2e355436e5d03b22383ed60cf13cd0c18fbfe3dcbcf" -dependencies = [ - "async-trait", - "axum-core", - "bytes", - "futures-util", - "http", - "http-body", - "http-body-util", - "itoa", - "matchit", - "memchr", - "mime", - "percent-encoding", - "pin-project-lite", - "rustversion", - "serde", - "serde_json", - "serde_path_to_error", - "serde_urlencoded", - "sync_wrapper 1.0.1", - "tower", - "tower-layer", - "tower-service", -] - -[[package]] -name = "axum-core" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a15c63fd72d41492dc4f497196f5da1fb04fb7529e631d73630d1b491e47a2e3" -dependencies = [ - "async-trait", - "bytes", - "futures-util", - "http", - "http-body", - "http-body-util", - "mime", - "pin-project-lite", - "rustversion", - "sync_wrapper 0.1.2", - "tower-layer", - "tower-service", -] +checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" [[package]] name = "backtrace" @@ -114,6 +64,18 @@ version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" +[[package]] +name = "bb8" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b10cf871f3ff2ce56432fddc2615ac7acc3aa22ca321f8fea800846fbb32f188" +dependencies = [ + "async-trait", + "futures-util", + "parking_lot", + "tokio", +] + [[package]] name = "bitflags" version = "1.3.2" @@ -135,6 +97,12 @@ dependencies = [ "generic-array", ] +[[package]] +name = "bumpalo" +version = "3.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" + [[package]] name = "byteorder" version = "1.5.0" @@ -143,15 +111,15 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.7.1" +version = "1.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8318a53db07bb3f8dca91a600466bdb3f2eaadeedfdbcf02e1accbad9271ba50" +checksum = "428d9aa8fbc0670b7b8d6030a7fadd0f86151cae55e4dbbece15f3780a3dfaf3" [[package]] name = "cc" -version = "1.1.18" +version = "1.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b62ac837cdb5cb22e10a256099b4fc502b1dfe560cb282963a974d7abd80e476" +checksum = "812acba72f0a070b003d3697490d2b55b837230ae7c6c6497f05cc2ddbb8d938" dependencies = [ "shlex", ] @@ -230,6 +198,20 @@ dependencies = [ "r2d2", ] +[[package]] +name = "diesel-async" +version = "0.5.0" +source = "git+https://github.com/weiznich/diesel_async?rev=5b8262b#5b8262b86d8ed0e13adbbc4aee39500b9931ef8d" +dependencies = [ + "async-trait", + "bb8", + "diesel", + "futures-util", + "scoped-futures", + "tokio", + "tokio-postgres", +] + [[package]] name = "diesel_derives" version = "2.2.3" @@ -289,18 +271,6 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7" -[[package]] -name = "filetime" -version = "0.2.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35c0522e981e68cbfa8c3f978441a5f34b30b96e146b33cd3359176b50fe8586" -dependencies = [ - "cfg-if", - "libc", - "libredox", - "windows-sys 0.59.0", -] - [[package]] name = "fnv" version = "1.0.7" @@ -316,12 +286,39 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "futures-channel" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" +dependencies = [ + "futures-core", + "futures-sink", +] + [[package]] name = "futures-core" version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" +[[package]] +name = "futures-macro" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "futures-sink" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" + [[package]] name = "futures-task" version = "0.3.30" @@ -335,6 +332,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" dependencies = [ "futures-core", + "futures-macro", + "futures-sink", "futures-task", "pin-project-lite", "pin-utils", @@ -364,9 +363,9 @@ dependencies = [ [[package]] name = "gimli" -version = "0.31.0" +version = "0.31.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32085ea23f3234fc7846555e85283ba4de91e21016dc0455a16286d87a292d64" +checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" [[package]] name = "heck" @@ -389,15 +388,6 @@ dependencies = [ "digest", ] -[[package]] -name = "home" -version = "0.5.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5" -dependencies = [ - "windows-sys 0.52.0", -] - [[package]] name = "http" version = "1.1.0" @@ -409,34 +399,11 @@ dependencies = [ "itoa", ] -[[package]] -name = "http-body" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" -dependencies = [ - "bytes", - "http", -] - -[[package]] -name = "http-body-util" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f" -dependencies = [ - "bytes", - "futures-util", - "http", - "http-body", - "pin-project-lite", -] - [[package]] name = "httparse" -version = "1.9.4" +version = "1.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fcc0b4a115bf80b728eb8ea024ad5bd707b615bfed49e0665b6e0f86fd082d9" +checksum = "7d71d3574edd2771538b901e6549113b4006ece66150fb69c0fb6d9a2adae946" [[package]] name = "httpdate" @@ -472,11 +439,20 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9028f49264629065d057f340a86acb84867925865f73bbf8d47b4d149a7e88b8" +[[package]] +name = "js-sys" +version = "0.3.70" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1868808506b929d7b0cfa8f75951347aa71bb21144b7791bae35d9bccfcfe37a" +dependencies = [ + "wasm-bindgen", +] + [[package]] name = "libc" -version = "0.2.158" +version = "0.2.159" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439" +checksum = "561d97a539a36e26a9a5fad1ea11a3039a67714694aaa379433e580854bc3dc5" [[package]] name = "libmimalloc-sys" @@ -488,17 +464,6 @@ dependencies = [ "libc", ] -[[package]] -name = "libredox" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" -dependencies = [ - "bitflags 2.6.0", - "libc", - "redox_syscall", -] - [[package]] name = "lock_api" version = "0.4.12" @@ -515,12 +480,6 @@ version = "0.4.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" -[[package]] -name = "matchit" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94" - [[package]] name = "md-5" version = "0.10.6" @@ -546,12 +505,6 @@ dependencies = [ "libmimalloc-sys", ] -[[package]] -name = "mime" -version = "0.3.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" - [[package]] name = "miniz_oxide" version = "0.8.0" @@ -569,7 +522,7 @@ dependencies = [ "hermit-abi", "libc", "wasi", - "windows-sys 0.52.0", + "windows-sys", ] [[package]] @@ -583,18 +536,21 @@ dependencies = [ [[package]] name = "object" -version = "0.36.4" +version = "0.36.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "084f1a5821ac4c651660a94a7153d27ac9d8a53736203f58b31945ded098070a" +checksum = "aedf0a2d09c573ed1d8d85b30c119153926a2b36dce0ab28322c09a117a4683e" dependencies = [ "memchr", ] [[package]] name = "once_cell" -version = "1.19.0" +version = "1.20.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" +checksum = "82881c4be219ab5faaf2ad5e5e5ecdff8c66bd7402ca3160975c93b24961afd1" +dependencies = [ + "portable-atomic", +] [[package]] name = "parking_lot" @@ -643,26 +599,6 @@ dependencies = [ "siphasher", ] -[[package]] -name = "pin-project" -version = "1.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6bf43b791c5b9e34c3d182969b4abb522f9343702850a2e57f460d00d09b4b3" -dependencies = [ - "pin-project-internal", -] - -[[package]] -name = "pin-project-internal" -version = "1.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "pin-project-lite" version = "0.2.14" @@ -675,6 +611,12 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" +[[package]] +name = "portable-atomic" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc9c68a3f6da06753e9335d63e27f6b9754dd1920d941135b7ea8224f141adb2" + [[package]] name = "postgres-protocol" version = "0.6.7" @@ -695,9 +637,9 @@ dependencies = [ [[package]] name = "postgres-types" -version = "0.2.7" +version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02048d9e032fb3cc3413bbf7b83a15d84a5d419778e2628751896d856498eee9" +checksum = "f66ea23a2d0e5734297357705193335e0a957696f34bed2f2faefacb2fec336f" dependencies = [ "bytes", "fallible-iterator", @@ -715,9 +657,9 @@ dependencies = [ [[package]] name = "pq-sys" -version = "0.6.2" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a92c30dd81695321846d4dfe348da67b1752ebb61cd1549d203a7b57e323c435" +checksum = "f6cc05d7ea95200187117196eee9edd0644424911821aeb28a18ce60ea0b8793" dependencies = [ "vcpkg", ] @@ -783,9 +725,9 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.5.4" +version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0884ad60e090bf1345b93da0a5de8923c93884cd03f40dfcfddd3b4bee661853" +checksum = "9b6dfecf2c74bce2466cabf93f6664d6998a69eb21e39f4207930065b27b771f" dependencies = [ "bitflags 2.6.0", ] @@ -796,12 +738,6 @@ version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" -[[package]] -name = "rustversion" -version = "1.0.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6" - [[package]] name = "ryu" version = "1.0.18" @@ -816,41 +752,26 @@ checksum = "d4d5cd6d4f24f3ab107e949ab424738cf55b03deddce3b184c46985d7b1394ef" dependencies = [ "itoap", "ryu", - "sailfish-macros", "version_check", ] [[package]] -name = "sailfish-compiler" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7254ec7b3651f7f723a9073153f5dcddc1f2bf1bf8d1b23ac71c236ef6360d2b" -dependencies = [ - "filetime", - "home", - "memchr", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "sailfish-macros" -version = "0.9.0" +name = "scheduled-thread-pool" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00812289fe1891c191cc2d9db461352fc410619e07ec2bb748faaa06412619d0" +checksum = "3cbc66816425a074528352f5789333ecff06ca41b36b0b0efdfbb29edc391a19" dependencies = [ - "proc-macro2", - "sailfish-compiler", + "parking_lot", ] [[package]] -name = "scheduled-thread-pool" -version = "0.2.7" +name = "scoped-futures" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3cbc66816425a074528352f5789333ecff06ca41b36b0b0efdfbb29edc391a19" +checksum = "b1473e24c637950c9bd38763220bea91ec3e095a89f672bbd7a10d03e77ba467" dependencies = [ - "parking_lot", + "cfg-if", + "pin-utils", ] [[package]] @@ -891,16 +812,6 @@ dependencies = [ "serde", ] -[[package]] -name = "serde_path_to_error" -version = "0.1.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af99884400da37c88f5e9146b7f1fd0fbcae8f6eec4e9da38b67d05486f814a6" -dependencies = [ - "itoa", - "serde", -] - [[package]] name = "serde_urlencoded" version = "0.7.1" @@ -977,7 +888,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c" dependencies = [ "libc", - "windows-sys 0.52.0", + "windows-sys", ] [[package]] @@ -1005,27 +916,15 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "syn" -version = "2.0.77" +version = "2.0.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f35bcdf61fd8e7be6caf75f429fdca8beb3ed76584befb503b1569faee373ed" +checksum = "89132cd0bf050864e1d38dc3bbc07a0eb8e7530af26344d3d2bbbef83499f590" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] -[[package]] -name = "sync_wrapper" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" - -[[package]] -name = "sync_wrapper" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7065abeca94b6a8a577f9bd45aa0867a2238b74e8eb67cf10d492bc39351394" - [[package]] name = "tinyvec" version = "1.8.0" @@ -1048,13 +947,40 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2b070231665d27ad9ec9b8df639893f46727666c6767db40317fbe920a5d998" dependencies = [ "backtrace", + "bytes", "libc", "mio", "parking_lot", "pin-project-lite", "signal-hook-registry", "socket2 0.5.7", - "windows-sys 0.52.0", + "windows-sys", +] + +[[package]] +name = "tokio-postgres" +version = "0.7.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b5d3742945bc7d7f210693b0c58ae542c6fd47b17adbbda0885f3dcb34a6bdb" +dependencies = [ + "async-trait", + "byteorder", + "bytes", + "fallible-iterator", + "futures-channel", + "futures-util", + "log", + "parking_lot", + "percent-encoding", + "phf", + "pin-project-lite", + "postgres-protocol", + "postgres-types", + "rand", + "socket2 0.5.7", + "tokio", + "tokio-util", + "whoami", ] [[package]] @@ -1073,55 +999,24 @@ dependencies = [ ] [[package]] -name = "tower" -version = "0.4.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" -dependencies = [ - "futures-core", - "futures-util", - "pin-project", - "pin-project-lite", - "tower-layer", - "tower-service", - "tracing", -] - -[[package]] -name = "tower-http" -version = "0.5.2" +name = "tokio-util" +version = "0.7.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e9cd434a998747dd2c4276bc96ee2e0c7a2eadf3cae88e52be55a05fa9053f5" +checksum = "61e7c3654c13bcd040d4a03abee2c75b1d14a37b423cf5a813ceae1cc903ec6a" dependencies = [ - "bitflags 2.6.0", "bytes", - "http", - "http-body", - "http-body-util", + "futures-core", + "futures-sink", "pin-project-lite", - "tower-layer", - "tower-service", + "tokio", ] -[[package]] -name = "tower-layer" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" - -[[package]] -name = "tower-service" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" - [[package]] name = "tracing" version = "0.1.40" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" dependencies = [ - "log", "pin-project-lite", "tracing-core", ] @@ -1131,9 +1026,6 @@ name = "tracing-core" version = "0.1.32" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" -dependencies = [ - "once_cell", -] [[package]] name = "typenum" @@ -1143,9 +1035,9 @@ checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" [[package]] name = "unicode-bidi" -version = "0.3.15" +version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" +checksum = "5ab17db44d7388991a428b2ee655ce0c212e862eff1768a455c58f9aad6e7893" [[package]] name = "unicode-ident" @@ -1155,18 +1047,18 @@ checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" [[package]] name = "unicode-normalization" -version = "0.1.23" +version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5" +checksum = "5033c97c4262335cded6d6fc3e5c18ab755e1a3dc96376350f3d8e9f009ad956" dependencies = [ "tinyvec", ] [[package]] name = "unicode-properties" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52ea75f83c0137a9b98608359a5f1af8144876eb67bcb1ce837368e906a9f524" +checksum = "e70f2a8b45122e719eb623c01822704c4e0907e7e426a05927e1a1cfff5b75d0" [[package]] name = "vcpkg" @@ -1186,6 +1078,88 @@ version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +[[package]] +name = "wasite" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8dad83b4f25e74f184f64c43b150b91efe7647395b42289f38e50566d82855b" + +[[package]] +name = "wasm-bindgen" +version = "0.2.93" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a82edfc16a6c469f5f44dc7b571814045d60404b55a0ee849f9bcfa2e63dd9b5" +dependencies = [ + "cfg-if", + "once_cell", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.93" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9de396da306523044d3302746f1208fa71d7532227f15e347e2d93e4145dd77b" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.93" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "585c4c91a46b072c92e908d99cb1dcdf95c5218eeb6f3bf1efa991ee7a68cccf" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.93" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.93" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c62a0a307cb4a311d3a07867860911ca130c3494e8c2719593806c08bc5d0484" + +[[package]] +name = "web-sys" +version = "0.3.70" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26fdeaafd9bd129f65e7c031593c24d62186301e0c72c8978fa1678be7d532c0" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "whoami" +version = "1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "372d5b87f58ec45c384ba03563b03544dc5fadc3983e434b286913f5b4a9bb6d" +dependencies = [ + "redox_syscall", + "wasite", + "web-sys", +] + [[package]] name = "winapi" version = "0.3.9" @@ -1217,15 +1191,6 @@ dependencies = [ "windows-targets", ] -[[package]] -name = "windows-sys" -version = "0.59.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" -dependencies = [ - "windows-targets", -] - [[package]] name = "windows-targets" version = "0.52.6" @@ -1292,9 +1257,8 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "xitca-codegen" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "336b646a30e6d44093beaae1bbe5dda664e8466d387663fc9d61c55fb2d78424" +version = "0.4.0" +source = "git+http://github.com/HFQR/xitca-web?rev=d3066ba#d3066ba5fc65e89c8a20890dd529f05818c853d6" dependencies = [ "quote", "syn", @@ -1302,9 +1266,8 @@ dependencies = [ [[package]] name = "xitca-http" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47b5b036e32261c69d4f0e81bcb28c2e058ed569518959336fd75fc086208d3f" +version = "0.7.0" +source = "git+http://github.com/HFQR/xitca-web?rev=d3066ba#d3066ba5fc65e89c8a20890dd529f05818c853d6" dependencies = [ "futures-core", "http", @@ -1336,12 +1299,13 @@ dependencies = [ [[package]] name = "xitca-postgres" -version = "0.1.0" -source = "git+https://github.com/HFQR/xitca-web.git?rev=0cda225#0cda2254f98b40f21bc3170dd8983f16444f0bd0" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46046cb7a3d4fcfb5c858bab0651c73bb45c0c5f9f0f53dd4eb991f2d6e5d6f4" dependencies = [ "fallible-iterator", + "futures-core", "percent-encoding", - "phf", "postgres-protocol", "postgres-types", "tokio", @@ -1350,6 +1314,19 @@ dependencies = [ "xitca-unsafe-collection", ] +[[package]] +name = "xitca-postgres-diesel" +version = "0.1.0" +source = "git+https://github.com/fakeshadow/xitca-postgres-diesel?rev=ae93ee9#ae93ee95277e281fb87b351c42bfc2fc5a56703a" +dependencies = [ + "diesel", + "diesel-async", + "futures-core", + "scoped-futures", + "tokio", + "xitca-postgres", +] + [[package]] name = "xitca-router" version = "0.3.0" @@ -1361,9 +1338,8 @@ dependencies = [ [[package]] name = "xitca-server" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a40a05f18780f1de843c5077583e4650b08d0518fcf9cf7948e28bc92e489736" +version = "0.5.0" +source = "git+http://github.com/HFQR/xitca-web?rev=d3066ba#d3066ba5fc65e89c8a20890dd529f05818c853d6" dependencies = [ "socket2 0.5.7", "tokio", @@ -1376,9 +1352,8 @@ dependencies = [ [[package]] name = "xitca-service" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74b093ca75b264924773d53e445de08a937100bf1cbe4f62d4dc2c0d04a3ba4b" +version = "0.3.0" +source = "git+http://github.com/HFQR/xitca-web?rev=d3066ba#d3066ba5fc65e89c8a20890dd529f05818c853d6" [[package]] name = "xitca-unsafe-collection" @@ -1394,42 +1369,39 @@ name = "xitca-web" version = "0.1.0" dependencies = [ "atoi", - "axum", "diesel", + "diesel-async", "futures-core", - "http-body", + "futures-util", + "httparse", "mimalloc", "rand", "sailfish", "serde", "serde_json", "tokio", - "tower", - "tower-http", + "tokio-uring", "xitca-http", "xitca-io", "xitca-postgres", + "xitca-postgres-diesel", "xitca-server", "xitca-service", "xitca-unsafe-collection", - "xitca-web 0.6.2", + "xitca-web 0.7.0", ] [[package]] name = "xitca-web" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd4f8f16791ea2a8845f617f1e87887f917835e0603d01f03a51e638b9613d0c" +version = "0.7.0" +source = "git+http://github.com/HFQR/xitca-web?rev=d3066ba#d3066ba5fc65e89c8a20890dd529f05818c853d6" dependencies = [ "futures-core", - "http-body", "pin-project-lite", "serde", "serde_json", "serde_urlencoded", "tokio", - "tower-layer", - "tower-service", "xitca-codegen", "xitca-http", "xitca-server", diff --git a/frameworks/Rust/xitca-web/Cargo.toml b/frameworks/Rust/xitca-web/Cargo.toml index 6c16d2d7a54..03d7098e796 100644 --- a/frameworks/Rust/xitca-web/Cargo.toml +++ b/frameworks/Rust/xitca-web/Cargo.toml @@ -19,9 +19,9 @@ path = "./src/main_wasm.rs" required-features = ["web"] [[bin]] -name = "xitca-web-axum" -path = "./src/main_axum.rs" -required-features = ["axum", "io-uring", "perf", "pg-sync", "template"] +name = "xitca-web-orm" +path = "./src/main_orm.rs" +required-features = ["pg-orm-async", "template", "web-codegen"] [[bin]] name = "xitca-web-sync" @@ -29,55 +29,56 @@ path = "./src/main_sync.rs" required-features = ["pg-orm", "template", "web-codegen"] [features] -# pg optional +# pg client optional pg = ["dep:xitca-postgres"] -# pg send/sync optional -pg-sync = ["dep:xitca-postgres"] -# pg orm optional -pg-orm = ["dep:diesel"] +# diesel orm optional +pg-orm = ["diesel/r2d2"] +# diesel async orm optional +pg-orm-async = ["dep:diesel", "dep:diesel-async", "dep:xitca-postgres-diesel", "futures-util"] # http router optional router = ["xitca-http/router"] # web optional web = ["dep:xitca-web"] -# web codegen optional +# web with macros optional web-codegen = ["xitca-web/codegen", "xitca-web/urlencoded"] # template optional template = ["dep:sailfish"] # io-uring optional -io-uring = ["xitca-http/io-uring", "xitca-server/io-uring"] -# axum optional -axum = ["dep:axum", "dep:http-body", "dep:tower", "dep:tower-http", "xitca-web/tower-http-compat" ] +io-uring = ["dep:tokio-uring", "xitca-http/io-uring", "xitca-server/io-uring"] # unrealistic performance optimization perf = ["dep:mimalloc", "tokio/parking_lot"] [dependencies] -xitca-http = "0.6" -xitca-io = "0.4" -xitca-server = "0.4" -xitca-service = "0.2" +xitca-http = "0.7" +xitca-io = "0.4.1" +xitca-server = "0.5" +xitca-service = "0.3" xitca-unsafe-collection = "0.2" atoi = "2" +httparse = "1" serde = { version = "1" } serde_json = { version = "1" } # web optional -xitca-web = { version = "0.6", features = ["json"], optional = true } +xitca-web = { version = "0.7", features = ["json"], optional = true } # raw-pg optional -xitca-postgres = { version = "0.1", optional = true } +xitca-postgres = { version = "0.2", optional = true } # orm optional -diesel = { version = "2", features = ["postgres", "r2d2"], optional = true } +diesel = { version = "2", features = ["postgres"], optional = true } + +# orm async optional +diesel-async = { version = "0.5", features = ["bb8", "postgres"], optional = true } +xitca-postgres-diesel = { version = "0.1", optional = true } +futures-util = { version = "0.3", default-features = false, optional = true } # template optional -sailfish = { version = "0.9", default-features = false, features = ["derive", "perf-inline"], optional = true } +sailfish = { version = "0.9", default-features = false, features = ["perf-inline"], optional = true } -# axum optional -axum = { version = "0.7", optional = true, default-features = false, features = ["json", "query"] } -http-body = { version = "1", optional = true } -tower = { version = "0.4", optional = true } -tower-http = { version = "0.5", features = ["set-header"], optional = true } +# io-uring optional +tokio-uring = { version = "0.5", optional = true } # perf optional mimalloc = { version = "0.1", default-features = false, optional = true } @@ -95,5 +96,13 @@ codegen-units = 1 panic = "abort" [patch.crates-io] -xitca-postgres = { git = "https://github.com/HFQR/xitca-web.git", rev = "0cda225" } +xitca-postgres-diesel = { git = "https://github.com/fakeshadow/xitca-postgres-diesel", rev = "ae93ee9" } + +diesel-async = { git = "https://github.com/weiznich/diesel_async", rev = "5b8262b" } mio = { git = "https://github.com/fakeshadow/mio", rev = "9bae6012b7ecfc6083350785f71a5e8265358178" } + +xitca-codegen = { git = "http://github.com/HFQR/xitca-web", rev = "d3066ba" } +xitca-http = { git = "http://github.com/HFQR/xitca-web", rev = "d3066ba" } +xitca-server = { git = "http://github.com/HFQR/xitca-web", rev = "d3066ba" } +xitca-service = { git = "http://github.com/HFQR/xitca-web", rev = "d3066ba" } +xitca-web = { git = "http://github.com/HFQR/xitca-web", rev = "d3066ba" } diff --git a/frameworks/Rust/xitca-web/benchmark_config.json b/frameworks/Rust/xitca-web/benchmark_config.json index f4c152eb729..973d1961472 100755 --- a/frameworks/Rust/xitca-web/benchmark_config.json +++ b/frameworks/Rust/xitca-web/benchmark_config.json @@ -35,14 +35,14 @@ "approach": "Stripped", "classification": "Platform", "database": "Postgres", - "framework": "xitca-web [unrealistic]", + "framework": "xitca-web", "language": "Rust", "orm": "Raw", "platform": "None", "webserver": "xitca-server", "os": "Linux", "database_os": "Linux", - "display_name": "xitca-web [unrealistic]", + "display_name": "xitca-web [iou]", "notes": "", "versus": "" }, @@ -53,7 +53,7 @@ "approach": "Realistic", "classification": "Micro", "database": "none", - "framework": "xitca-web [wasm]", + "framework": "xitca-web", "language": "rust", "orm": "raw", "platform": "none", @@ -64,7 +64,7 @@ "notes": "", "versus": "" }, - "axum": { + "orm": { "json_url": "/json", "plaintext_url": "/plaintext", "db_url": "/db", @@ -73,16 +73,16 @@ "update_url": "/updates?q=", "port": 8080, "approach": "realistic", - "classification": "micro", + "classification": "fullstack", "database": "postgres", - "framework": "axum [xitca]", + "framework": "xitca-web", "language": "rust", - "orm": "raw", + "orm": "full", "platform": "none", "webserver": "xitca-server", "os": "linux", "database_os": "linux", - "display_name": "axum [xitca]", + "display_name": "xitca-web [orm]", "notes": "", "versus": "" }, @@ -97,7 +97,7 @@ "approach": "realistic", "classification": "micro", "database": "postgres", - "framework": "xitca-web [sync]", + "framework": "xitca-web", "language": "rust", "orm": "full", "platform": "none", diff --git a/frameworks/Rust/xitca-web/src/db.rs b/frameworks/Rust/xitca-web/src/db.rs index 818804341b1..ad75d6f8bbe 100644 --- a/frameworks/Rust/xitca-web/src/db.rs +++ b/frameworks/Rust/xitca-web/src/db.rs @@ -1,101 +1,63 @@ -// clippy is dumb and have no idea what should be lazy or not -#![allow(clippy::unnecessary_lazy_evaluations)] +#[path = "./db_util.rs"] +mod db_util; -use xitca_io::bytes::BytesMut; -use xitca_postgres::{pipeline::Pipeline, pool::Pool, AsyncLendingIterator, Type}; +use std::cell::RefCell; + +use xitca_postgres::{ + iter::AsyncLendingIterator, pipeline::Pipeline, pool::Pool, statement::Statement, Execute, ExecuteMut, +}; use super::{ ser::{Fortune, Fortunes, World}, - util::{bulk_update_gen, HandleResult, Rand, DB_URL}, + util::{HandleResult, DB_URL}, }; +use db_util::{sort_update_params, update_query, Shared, FORTUNE_STMT, WORLD_STMT}; + pub struct Client { pool: Pool, - #[cfg(not(feature = "pg-sync"))] - shared: std::cell::RefCell, - #[cfg(feature = "pg-sync")] - shared: std::sync::Mutex, + shared: RefCell, updates: Box<[Box]>, } -type Shared = (Rand, BytesMut); - -const FORTUNE_SQL: &str = "SELECT * FROM fortune"; - -const FORTUNE_SQL_TYPES: &[Type] = &[]; - -const WORLD_SQL: &str = "SELECT * FROM world WHERE id=$1"; - -const WORLD_SQL_TYPES: &[Type] = &[Type::INT4]; - -fn update_query(num: usize) -> Box { - bulk_update_gen(|query| { - use std::fmt::Write; - (1..=num).fold((1, query), |(idx, query), _| { - write!(query, "(${}::int,${}::int),", idx, idx + 1).unwrap(); - (idx + 2, query) - }); - }) - .into_boxed_str() -} - pub async fn create() -> HandleResult { - let pool = Pool::builder(DB_URL).capacity(1).build()?; - - let shared = (Rand::default(), BytesMut::new()); - - let updates = core::iter::once(Box::from("")) - .chain((1..=500).map(update_query)) - .collect(); - Ok(Client { - pool, - #[cfg(not(feature = "pg-sync"))] - shared: std::cell::RefCell::new(shared), - #[cfg(feature = "pg-sync")] - shared: std::sync::Mutex::new(shared), - updates, + pool: Pool::builder(DB_URL).capacity(1).build()?, + shared: Default::default(), + updates: core::iter::once(Box::from("")) + .chain((1..=500).map(update_query)) + .collect(), }) } impl Client { - #[cfg(not(feature = "pg-sync"))] - fn shared(&self) -> std::cell::RefMut<'_, Shared> { - self.shared.borrow_mut() - } - - #[cfg(feature = "pg-sync")] - fn shared(&self) -> std::sync::MutexGuard<'_, Shared> { - self.shared.lock().unwrap() - } - pub async fn get_world(&self) -> HandleResult { let mut conn = self.pool.get().await?; - let stmt = conn.prepare(WORLD_SQL, WORLD_SQL_TYPES).await?; - let id = self.shared().0.gen_id(); - let mut res = conn.consume().query_raw(&stmt, [id])?; - let row = res.try_next().await?.ok_or_else(|| "World does not exist")?; - Ok(World::new(row.get_raw(0), row.get_raw(1))) + let stmt = WORLD_STMT.execute_mut(&mut conn).await?; + let id = self.shared.borrow_mut().0.gen_id(); + let mut res = stmt.bind([id]).query(&conn.consume()).await?; + let row = res.try_next().await?.ok_or("request World does not exist")?; + Ok(World::new(row.get(0), row.get(1))) } pub async fn get_worlds(&self, num: u16) -> HandleResult> { let len = num as usize; let mut conn = self.pool.get().await?; - let stmt = conn.prepare(WORLD_SQL, WORLD_SQL_TYPES).await?; + let stmt = WORLD_STMT.execute_mut(&mut conn).await?; let mut res = { - let (ref mut rng, ref mut buf) = *self.shared(); + let (ref mut rng, ref mut buf) = *self.shared.borrow_mut(); let mut pipe = Pipeline::with_capacity_from_buf(len, buf); - (0..num).try_for_each(|_| pipe.query_raw(&stmt, [rng.gen_id()]))?; - conn.consume().pipeline(pipe)? + (0..num).try_for_each(|_| stmt.bind([rng.gen_id()]).query_mut(&mut pipe))?; + pipe.query(&conn.consume())? }; let mut worlds = Vec::with_capacity(len); while let Some(mut item) = res.try_next().await? { while let Some(row) = item.try_next().await? { - worlds.push(World::new(row.get_raw(0), row.get_raw(1))) + worlds.push(World::new(row.get(0), row.get(1))) } } @@ -105,25 +67,24 @@ impl Client { pub async fn update(&self, num: u16) -> HandleResult> { let len = num as usize; - let update = self.updates.get(len).ok_or_else(|| "num out of bound")?; - + let update = self.updates.get(len).ok_or("request num is out of range")?; let mut conn = self.pool.get().await?; - let world_stmt = conn.prepare(WORLD_SQL, WORLD_SQL_TYPES).await?; - let update_stmt = conn.prepare(update, &[]).await?; + let world_stmt = WORLD_STMT.execute_mut(&mut conn).await?; + let update_stmt = Statement::named(update, &[]).execute_mut(&mut conn).await?; let mut params = Vec::with_capacity(len); let mut res = { - let (ref mut rng, ref mut buf) = *self.shared(); + let (ref mut rng, ref mut buf) = *self.shared.borrow_mut(); let mut pipe = Pipeline::with_capacity_from_buf(len + 1, buf); (0..num).try_for_each(|_| { let w_id = rng.gen_id(); let r_id = rng.gen_id(); params.push([w_id, r_id]); - pipe.query_raw(&world_stmt, [w_id]) + world_stmt.bind([w_id]).query_mut(&mut pipe) })?; - pipe.query_raw(&update_stmt, sort_update_params(¶ms))?; - conn.consume().pipeline(pipe)? + update_stmt.bind(sort_update_params(¶ms)).query_mut(&mut pipe)?; + pipe.query(&conn.consume())? }; let mut worlds = Vec::with_capacity(len); @@ -133,7 +94,7 @@ impl Client { while let Some(mut item) = res.try_next().await? { while let Some(row) = item.try_next().await? { let r_id = r_ids.next().unwrap()[1]; - worlds.push(World::new(row.get_raw(0), r_id)) + worlds.push(World::new(row.get(0), r_id)) } } @@ -145,11 +106,11 @@ impl Client { items.push(Fortune::new(0, "Additional fortune added at request time.")); let mut conn = self.pool.get().await?; - let stmt = conn.prepare(FORTUNE_SQL, FORTUNE_SQL_TYPES).await?; - let mut res = conn.consume().query_raw::<[i32; 0]>(&stmt, [])?; + let stmt = FORTUNE_STMT.execute_mut(&mut conn).await?; + let mut res = stmt.query(&conn.consume()).await?; while let Some(row) = res.try_next().await? { - items.push(Fortune::new(row.get_raw(0), row.get_raw::(1))); + items.push(Fortune::new(row.get(0), row.get::(1))); } items.sort_by(|it, next| it.message.cmp(&next.message)); @@ -157,33 +118,3 @@ impl Client { Ok(Fortunes::new(items)) } } - -fn sort_update_params(params: &[[i32; 2]]) -> impl ExactSizeIterator { - let mut params = params.to_owned(); - params.sort_by(|a, b| a[0].cmp(&b[0])); - - struct ParamIter(I); - - impl Iterator for ParamIter - where - I: Iterator, - { - type Item = I::Item; - - #[inline] - fn next(&mut self) -> Option { - self.0.next() - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - self.0.size_hint() - } - } - - // impl depends on compiler optimization to flat Vec<[T]> to Vec when inferring - // it's size hint. possible to cause runtime panic. - impl ExactSizeIterator for ParamIter where I: Iterator {} - - ParamIter(params.into_iter().flatten()) -} diff --git a/frameworks/Rust/xitca-web/src/db_diesel_async.rs b/frameworks/Rust/xitca-web/src/db_diesel_async.rs new file mode 100644 index 00000000000..fdd93e43a74 --- /dev/null +++ b/frameworks/Rust/xitca-web/src/db_diesel_async.rs @@ -0,0 +1,153 @@ +use std::{ + io, + sync::{Arc, Mutex}, +}; + +use diesel::prelude::*; +use diesel_async::{ + pooled_connection::{bb8, AsyncDieselConnectionManager}, + RunQueryDsl, +}; +use futures_util::{ + future::join, + stream::{FuturesUnordered, TryStreamExt}, +}; +use xitca_postgres_diesel::AsyncPgConnection; + +use crate::{ + ser::{Fortune, Fortunes, World}, + util::{bulk_update_gen, Error, HandleResult, Rand, DB_URL}, +}; + +pub type Pool = Arc<_Pool>; + +pub struct _Pool { + pool: bb8::Pool, + rng: Mutex, +} + +pub async fn create() -> io::Result> { + bb8::Pool::builder() + .max_size(1) + .min_idle(Some(1)) + .test_on_check_out(false) + .build(AsyncDieselConnectionManager::new(DB_URL)) + .await + .map_err(io::Error::other) + .map(|pool| { + Arc::new(_Pool { + pool, + rng: Mutex::new(Rand::default()), + }) + }) +} + +#[cold] +#[inline(never)] +fn not_found() -> Error { + "world not found".into() +} + +impl _Pool { + pub async fn get_world(&self) -> HandleResult { + use crate::schema::world::dsl::*; + { + let w_id = self.rng.lock().unwrap().gen_id(); + let mut conn = self.pool.get().await?; + world.filter(id.eq(w_id)).load(&mut conn) + } + .await? + .pop() + .ok_or_else(not_found) + } + + pub async fn get_worlds(&self, num: u16) -> HandleResult> { + use crate::schema::world::dsl::*; + { + let mut conn = self.pool.get().await?; + let mut rng = self.rng.lock().unwrap(); + (0..num) + .map(|_| { + let w_id = rng.gen_id(); + let fut = world.filter(id.eq(w_id)).load::(&mut conn); + async { fut.await?.pop().ok_or_else(not_found) } + }) + .collect::>() + } + .try_collect() + .await + } + + pub async fn update(&self, num: u16) -> HandleResult> { + use crate::schema::world::dsl::*; + + let mut rngs = Vec::with_capacity(num as _); + + let (select_res, update_res) = { + let mut conn = self.pool.get().await?; + + let mut rng = self.rng.lock().unwrap(); + + let select = (0..num) + .map(|_| { + let w_id = rng.gen_id(); + let num = rng.gen_id(); + + rngs.push((w_id, num)); + + let fut = world.filter(id.eq(w_id)).load::(&mut conn); + + async move { + fut.await? + .pop() + .map(|mut w| { + w.randomnumber = num; + w + }) + .ok_or_else(not_found) + } + }) + .collect::>(); + + rngs.sort_by(|(a, _), (b, _)| a.cmp(b)); + + let update = diesel::sql_query(update_query(&rngs)).execute(&mut conn); + + join(select.try_collect::>(), update) + } + .await; + + update_res?; + let mut worlds = select_res?; + + worlds.sort_by_key(|w| w.id); + + Ok(worlds) + } + + pub async fn tell_fortune(&self) -> HandleResult { + use crate::schema::fortune::dsl::*; + + let mut items = { + let mut conn = self.pool.get().await?; + fortune.load::(&mut conn) + } + .await?; + + items.push(Fortune::new(0, "Additional fortune added at request time.")); + items.sort_by(|it, next| it.message.cmp(&next.message)); + + Ok(Fortunes::new(items)) + } +} + +// diesel does not support high level bulk update api. use raw sql to bypass the limitation. +// relate discussion: https://github.com/diesel-rs/diesel/discussions/2879 +fn update_query(ids: &[(i32, i32)]) -> String { + bulk_update_gen(|query| { + use std::fmt::Write; + ids.iter().for_each(|(w_id, num)| { + write!(query, "({}::int,{}::int),", w_id, num).unwrap(); + }); + }) +} diff --git a/frameworks/Rust/xitca-web/src/db_unrealistic.rs b/frameworks/Rust/xitca-web/src/db_unrealistic.rs new file mode 100644 index 00000000000..7b04449a716 --- /dev/null +++ b/frameworks/Rust/xitca-web/src/db_unrealistic.rs @@ -0,0 +1,130 @@ +//! this module is unrealistic. related issue: +//! https://github.com/TechEmpower/FrameworkBenchmarks/issues/8790 + +#[path = "./db_util.rs"] +mod db_util; + +use std::cell::RefCell; + +use xitca_postgres::{iter::AsyncLendingIterator, pipeline::Pipeline, statement::Statement, Execute, ExecuteMut}; + +use super::{ + ser::{Fortune, Fortunes, World}, + util::{HandleResult, DB_URL}, +}; + +use db_util::{sort_update_params, update_query, Shared, FORTUNE_STMT, WORLD_STMT}; + +pub struct Client { + cli: xitca_postgres::Client, + shared: RefCell, + fortune: Statement, + world: Statement, + updates: Box<[Statement]>, +} + +pub async fn create() -> HandleResult { + let (cli, mut drv) = xitca_postgres::Postgres::new(DB_URL).connect().await?; + + tokio::task::spawn(tokio::task::unconstrained(async move { + while drv.try_next().await?.is_some() {} + HandleResult::Ok(()) + })); + + let world = WORLD_STMT.execute(&cli).await?.leak(); + let fortune = FORTUNE_STMT.execute(&cli).await?.leak(); + + let mut updates = vec![Statement::default()]; + + for update in (1..=500).map(update_query).into_iter() { + let stmt = Statement::named(&update, &[]).execute(&cli).await?.leak(); + updates.push(stmt); + } + + Ok(Client { + cli, + shared: Default::default(), + world, + fortune, + updates: updates.into_boxed_slice(), + }) +} + +impl Client { + pub async fn get_world(&self) -> HandleResult { + let id = self.shared.borrow_mut().0.gen_id(); + let mut res = self.world.bind([id]).query(&self.cli).await?; + let row = res.try_next().await?.ok_or("request World does not exist")?; + Ok(World::new(row.get(0), row.get(1))) + } + + pub async fn get_worlds(&self, num: u16) -> HandleResult> { + let len = num as usize; + + let mut res = { + let (ref mut rng, ref mut buf) = *self.shared.borrow_mut(); + let mut pipe = Pipeline::with_capacity_from_buf(len, buf); + (0..num).try_for_each(|_| self.world.bind([rng.gen_id()]).query_mut(&mut pipe))?; + pipe.query(&self.cli)? + }; + + let mut worlds = Vec::with_capacity(len); + + while let Some(mut item) = res.try_next().await? { + while let Some(row) = item.try_next().await? { + worlds.push(World::new(row.get(0), row.get(1))) + } + } + + Ok(worlds) + } + + pub async fn update(&self, num: u16) -> HandleResult> { + let len = num as usize; + + let mut params = Vec::with_capacity(len); + + let mut res = { + let (ref mut rng, ref mut buf) = *self.shared.borrow_mut(); + let mut pipe = Pipeline::with_capacity_from_buf(len + 1, buf); + (0..num).try_for_each(|_| { + let w_id = rng.gen_id(); + let r_id = rng.gen_id(); + params.push([w_id, r_id]); + self.world.bind([w_id]).query_mut(&mut pipe) + })?; + self.updates[len] + .bind(sort_update_params(¶ms)) + .query_mut(&mut pipe)?; + pipe.query(&self.cli)? + }; + + let mut worlds = Vec::with_capacity(len); + + let mut r_ids = params.into_iter(); + + while let Some(mut item) = res.try_next().await? { + while let Some(row) = item.try_next().await? { + let r_id = r_ids.next().unwrap()[1]; + worlds.push(World::new(row.get(0), r_id)) + } + } + + Ok(worlds) + } + + pub async fn tell_fortune(&self) -> HandleResult { + let mut items = Vec::with_capacity(32); + items.push(Fortune::new(0, "Additional fortune added at request time.")); + + let mut res = self.fortune.query(&self.cli).await?; + + while let Some(row) = res.try_next().await? { + items.push(Fortune::new(row.get(0), row.get::(1))); + } + + items.sort_by(|it, next| it.message.cmp(&next.message)); + + Ok(Fortunes::new(items)) + } +} diff --git a/frameworks/Rust/xitca-web/src/db_util.rs b/frameworks/Rust/xitca-web/src/db_util.rs new file mode 100644 index 00000000000..19879333427 --- /dev/null +++ b/frameworks/Rust/xitca-web/src/db_util.rs @@ -0,0 +1,53 @@ +use xitca_io::bytes::BytesMut; +use xitca_postgres::{ + statement::{Statement, StatementNamed}, + types::Type, +}; + +use crate::util::{bulk_update_gen, Rand}; + +pub(super) type Shared = (Rand, BytesMut); + +pub(super) const FORTUNE_STMT: StatementNamed = Statement::named("SELECT * FROM fortune", &[]); +pub(super) const WORLD_STMT: StatementNamed = Statement::named("SELECT * FROM world WHERE id=$1", &[Type::INT4]); + +pub(super) fn update_query(num: usize) -> Box { + bulk_update_gen(|query| { + use std::fmt::Write; + (1..=num).fold((1, query), |(idx, query), _| { + write!(query, "(${}::int,${}::int),", idx, idx + 1).unwrap(); + (idx + 2, query) + }); + }) + .into_boxed_str() +} + +pub(super) fn sort_update_params(params: &[[i32; 2]]) -> impl ExactSizeIterator { + let mut params = params.to_owned(); + params.sort_by(|a, b| a[0].cmp(&b[0])); + + struct ParamIter(I); + + impl Iterator for ParamIter + where + I: Iterator, + { + type Item = I::Item; + + #[inline] + fn next(&mut self) -> Option { + self.0.next() + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.0.size_hint() + } + } + + // impl depends on compiler optimization to flat Vec<[T]> to Vec when inferring + // it's size hint. possible to cause runtime panic. + impl ExactSizeIterator for ParamIter where I: Iterator {} + + ParamIter(params.into_iter().flatten()) +} diff --git a/frameworks/Rust/xitca-web/src/main.rs b/frameworks/Rust/xitca-web/src/main.rs index 710ff577586..b7389fbb821 100755 --- a/frameworks/Rust/xitca-web/src/main.rs +++ b/frameworks/Rust/xitca-web/src/main.rs @@ -5,18 +5,22 @@ mod util; use xitca_http::{ h1::RequestBody, http::{header::SERVER, StatusCode}, - util::service::{ - route::get, - router::{Router, RouterError}, + util::{ + middleware::context::{Context, ContextBuilder}, + service::{ + route::get, + router::{Router, RouterError}, + }, }, HttpServiceBuilder, }; use xitca_service::{fn_service, Service, ServiceExt}; +use db::Client; use ser::{error_response, IntoResponse, Message, Request, Response}; -use util::{context_mw, HandleResult, QueryParse, SERVER_HEADER_VALUE}; +use util::{HandleResult, QueryParse, State, SERVER_HEADER_VALUE}; -type Ctx<'a> = util::Ctx<'a, Request>; +type Ctx<'a> = Context<'a, Request, State>; fn main() -> std::io::Result<()> { let service = Router::new() @@ -27,7 +31,7 @@ fn main() -> std::io::Result<()> { .insert("/queries", get(fn_service(queries))) .insert("/updates", get(fn_service(updates))) .enclosed_fn(middleware) - .enclosed(context_mw()) + .enclosed(ContextBuilder::new(|| async { db::create().await.map(State::new) })) .enclosed(HttpServiceBuilder::h1().io_uring()); xitca_server::Builder::new() .bind("xitca-web", "0.0.0.0:8080", service)? diff --git a/frameworks/Rust/xitca-web/src/main_axum.rs b/frameworks/Rust/xitca-web/src/main_axum.rs deleted file mode 100644 index 02fdfba8a20..00000000000 --- a/frameworks/Rust/xitca-web/src/main_axum.rs +++ /dev/null @@ -1,150 +0,0 @@ -//! show case of axum running on proper thread per core server with io-uring enabled. - -#[global_allocator] -static GLOBAL: mimalloc::MiMalloc = mimalloc::MiMalloc; - -mod db; -mod ser; -mod util; - -use std::sync::Arc; - -use axum::{ - extract::{Json, Query, State}, - http::{ - header::{HeaderValue, SERVER}, - StatusCode, - }, - response::{Html, IntoResponse, Response}, - routing::{get, Router}, -}; -use tower_http::set_header::SetResponseHeaderLayer; - -use crate::{db::Client, ser::Num, tower_compat::TowerHttp}; - -fn main() -> std::io::Result<()> { - let service = TowerHttp::service(|| async { - let cli = db::create().await?; - let service = Router::new() - .route("/plaintext", get(plain_text)) - .route("/json", get(json)) - .route("/db", get(db)) - .route("/fortunes", get(fortunes)) - .route("/queries", get(queries)) - .route("/updates", get(updates)) - .with_state(Arc::new(cli)) - .layer(SetResponseHeaderLayer::if_not_present( - SERVER, - HeaderValue::from_static("A"), - )); - Ok(service) - }); - xitca_server::Builder::new() - .bind("xitca-axum", "0.0.0.0:8080", service)? - .build() - .wait() -} - -async fn plain_text() -> &'static str { - "Hello, World!" -} - -async fn json() -> impl IntoResponse { - Json(ser::Message::new()) -} - -async fn db(State(cli): State>) -> impl IntoResponse { - cli.get_world().await.map(Json).map_err(Error) -} - -async fn fortunes(State(cli): State>) -> impl IntoResponse { - use sailfish::TemplateOnce; - cli.tell_fortune() - .await - .map_err(Error)? - .render_once() - .map(Html) - .map_err(|e| Error(Box::new(e))) -} - -async fn queries(State(cli): State>, Query(Num(num)): Query) -> impl IntoResponse { - cli.get_worlds(num).await.map(Json).map_err(Error) -} - -async fn updates(State(cli): State>, Query(Num(num)): Query) -> impl IntoResponse { - cli.update(num).await.map(Json).map_err(Error) -} - -struct Error(util::Error); - -impl IntoResponse for Error { - fn into_response(self) -> Response { - let mut res = self.0.to_string().into_response(); - *res.status_mut() = StatusCode::INTERNAL_SERVER_ERROR; - res - } -} - -// compat module between xitca-http and axum. -mod tower_compat { - use core::{cell::RefCell, fmt, future::Future, marker::PhantomData}; - - use std::net::SocketAddr; - - use http_body::Body; - use xitca_http::{ - bytes::Bytes, - h1::RequestBody, - http::{Request, RequestExt, Response}, - HttpServiceBuilder, - }; - use xitca_io::net::io_uring::TcpStream; - use xitca_service::{fn_build, middleware::UncheckedReady, ready::ReadyService, Service, ServiceExt}; - use xitca_web::service::tower_http_compat::{CompatReqBody, CompatResBody}; - - pub struct TowerHttp { - service: RefCell, - _p: PhantomData, - } - - impl TowerHttp { - pub fn service( - func: F, - ) -> impl Service, Error = impl fmt::Debug> - where - F: Fn() -> Fut + Send + Sync + Clone, - Fut: Future>, - S: tower::Service, ()>>, Response = Response>, - S::Error: fmt::Debug, - B: Body + Send + 'static, - { - fn_build(move |_| { - let func = func.clone(); - async move { - func().await.map(|service| TowerHttp { - service: RefCell::new(service), - _p: PhantomData, - }) - } - }) - .enclosed(UncheckedReady) - .enclosed(HttpServiceBuilder::h1().io_uring()) - } - } - - impl Service>> for TowerHttp - where - S: tower::Service, ()>>, Response = Response>, - { - type Response = Response>; - type Error = S::Error; - - async fn call(&self, req: Request>) -> Result { - let (parts, ext) = req.into_parts(); - let req = Request::from_parts(parts, CompatReqBody::new(ext, ())); - let fut = self.service.borrow_mut().call(req); - let (parts, body) = fut.await?.into_parts(); - Ok(Response::from_parts(parts, CompatResBody::new(body))) - } - } -} diff --git a/frameworks/Rust/xitca-web/src/main_iou.rs b/frameworks/Rust/xitca-web/src/main_iou.rs index f66eb8778e6..7dcf6d1a719 100644 --- a/frameworks/Rust/xitca-web/src/main_iou.rs +++ b/frameworks/Rust/xitca-web/src/main_iou.rs @@ -1,9 +1,12 @@ -// used as reference of if/how moving from epoll to io-uring(or mixture of the two) make sense for -// network io. +// reference of if/how moving from epoll to io-uring(or mixture of the two) make sense for network io. +// with comment on explaining why some practice are unrealistic +// custom global memory allocator don't affect real world performance in noticeable amount. +// in real world they should be used for reason like security, debug/profiling capability etc. #[global_allocator] static GLOBAL: mimalloc::MiMalloc = mimalloc::MiMalloc; +#[path = "db_unrealistic.rs"] mod db; mod ser; mod util; @@ -11,53 +14,138 @@ mod util; use std::{convert::Infallible, io}; use xitca_http::{ - body::ResponseBody, - http::{self, header::SERVER, StatusCode}, - HttpServiceBuilder, + bytes::BufMutWriter, + h1::dispatcher_uring_unreal::{Dispatcher, Request, Response}, + http::StatusCode, }; -use xitca_service::{fn_service, ServiceExt}; +use xitca_io::net::io_uring::TcpStream; +use xitca_service::Service; -use self::{ - ser::{error_response, IntoResponse, Message, Request}, - util::{context_mw, Ctx, QueryParse, SERVER_HEADER_VALUE}, -}; +use self::{ser::Message, util::State}; fn main() -> io::Result<()> { - let service = fn_service(handler) - .enclosed(context_mw()) - .enclosed(HttpServiceBuilder::h1().io_uring()); - xitca_server::Builder::new() - .bind("xitca-iou", "0.0.0.0:8080", service)? - .build() - .wait() + let addr = "0.0.0.0:8080".parse().unwrap(); + + let cores = std::thread::available_parallelism().map(|num| num.get()).unwrap_or(56); + + let handle = core::iter::repeat_with(|| { + std::thread::spawn(move || { + tokio_uring::start(async { + let socket = tokio::net::TcpSocket::new_v4()?; + socket.set_reuseaddr(true)?; + // unrealistic due to following reason: + // 1. this only works good on unix system. + // 2. no resource distribution adjustment between sockets on different threads. causing uneven workload + // where some threads are idle while others busy. resulting in overall increased latency + socket.set_reuseport(true)?; + socket.bind(addr)?; + let listener = socket.listen(1024)?; + + let client = db::create().await.unwrap(); + + // unrealistic http dispatcher. no spec check. no security feature. + let service = Dispatcher::new(handler, State::new(client)); + + loop { + match listener.accept().await { + Ok((stream, _)) => { + let stream = stream.into_std()?; + let stream = TcpStream::from_std(stream); + let service = service.clone(); + tokio::task::spawn_local(async move { + let _ = service.call(stream).await; + }); + } + Err(e) => return Err(e), + }; + } + }) + }) + }) + .take(cores) + .collect::>(); + + // unrealistic due to no signal handling, not shutdown handling. when killing this process all resources that + // need clean async shutdown will be leaked. + for handle in handle { + handle.join().unwrap()?; + } + + Ok(()) } -async fn handler(ctx: Ctx<'_, Request>) -> Result, Infallible> { - let (req, state) = ctx.into_parts(); - let mut res = match req.uri().path() { - "/plaintext" => req.text_response().unwrap(), - "/json" => req.json_response(state, &Message::new()).unwrap(), +async fn handler<'h>(req: Request<'h, '_>, res: Response<'h>, state: &State) -> Response<'h, 3> { + // unrealistic due to no http method check + match req.path.unwrap_or("404") { + // unrealistic due to no dynamic path matching + "/plaintext" => { + // unrealistic due to no body streaming and no post processing. violating middleware feature of xitca-web + res.status(StatusCode::OK) + .header("content-type", "text/plain") + .header("server", "X") + // unrealistic content length header. + .header("content-length", "13") + .body_writer(|buf| Ok::<_, Infallible>(buf.extend_from_slice(b"Hello, World!"))) + .unwrap() + } + "/json" => res + .status(StatusCode::OK) + .header("content-type", "application/json") + .header("server", "X") + // unrealistic content length header. + .header("content-length", "27") + .body_writer(|buf| serde_json::to_writer(BufMutWriter(buf), &Message::new())) + .unwrap(), + // all database related categories are unrealistic. please reference db_unrealistic module for detail. + "/fortunes" => { + use sailfish::TemplateOnce; + let fortunes = state.client.tell_fortune().await.unwrap().render_once().unwrap(); + res.status(StatusCode::OK) + .header("content-type", "text/html; charset=utf-8") + .header("server", "X") + .body(fortunes.as_bytes()) + } "/db" => { + // unrealistic due to no error handling. any db/serialization error will cause process crash. + // the same goes for all following unwraps on database related functions. let world = state.client.get_world().await.unwrap(); - req.json_response(state, &world).unwrap() + json_response(res, state, &world) } - "/queries" => { - let num = req.uri().query().parse_query(); + p if p.starts_with("/queries") => { + let num = path_param(p); let worlds = state.client.get_worlds(num).await.unwrap(); - req.json_response(state, &worlds).unwrap() + json_response(res, state, &worlds) } - "/updates" => { - let num = req.uri().query().parse_query(); + p if p.starts_with("/updates") => { + let num = path_param(p); let worlds = state.client.update(num).await.unwrap(); - req.json_response(state, &worlds).unwrap() - } - "/fortunes" => { - use sailfish::TemplateOnce; - let fortunes = state.client.tell_fortune().await.unwrap().render_once().unwrap(); - req.html_response(fortunes).unwrap() + json_response(res, state, &worlds) } - _ => error_response(StatusCode::NOT_FOUND), + _ => res.status(StatusCode::NOT_FOUND).header("server", "X").body(&[]), + } +} + +fn json_response<'r, DB, T>(res: Response<'r>, state: &State, val: &T) -> Response<'r, 3> +where + T: serde::Serialize, +{ + let buf = &mut *state.write_buf.borrow_mut(); + serde_json::to_writer(BufMutWriter(buf), val).unwrap(); + let res = res + .status(StatusCode::OK) + .header("content-type", "application/json") + .header("server", "X") + .body(buf.as_ref()); + buf.clear(); + res +} + +fn path_param(query: &str) -> u16 { + use atoi::FromRadix10; + let q = if let Some(pos) = query.find("?q") { + u16::from_radix_10(query.split_at(pos + 3).1.as_ref()).0 + } else { + 1 }; - res.headers_mut().insert(SERVER, SERVER_HEADER_VALUE); - Ok(res.map(Into::into)) + q.clamp(1, 500) } diff --git a/frameworks/Rust/xitca-web/src/main_orm.rs b/frameworks/Rust/xitca-web/src/main_orm.rs new file mode 100644 index 00000000000..86e8037ac2e --- /dev/null +++ b/frameworks/Rust/xitca-web/src/main_orm.rs @@ -0,0 +1,67 @@ +mod db_diesel_async; +mod schema; +mod ser; +mod util; + +use serde::Serialize; +use xitca_web::{ + codegen::route, + handler::{html::Html, json::Json, query::Query, state::StateRef, text::Text}, + http::{header::SERVER, WebResponse}, + route::get, + App, +}; + +use db_diesel_async::Pool; +use ser::Num; +use util::{HandleResult, SERVER_HEADER_VALUE}; + +fn main() -> std::io::Result<()> { + App::new() + .with_async_state(db_diesel_async::create) + .at("/plaintext", get(Text("Hello, World!"))) + .at("/json", get(Json(ser::Message::new()))) + .at_typed(db) + .at_typed(fortunes) + .at_typed(queries) + .at_typed(updates) + .map(header) + .serve() + .disable_vectored_write() + .bind("0.0.0.0:8080")? + .run() + .wait() +} + +fn header(mut res: WebResponse) -> WebResponse { + res.headers_mut().insert(SERVER, SERVER_HEADER_VALUE); + res +} + +#[route("/db", method = get)] +async fn db(StateRef(pool): StateRef<'_, Pool>) -> HandleResult> { + pool.get_world().await.map(Json) +} + +#[route("/fortunes", method = get)] +async fn fortunes(StateRef(pool): StateRef<'_, Pool>) -> HandleResult> { + use sailfish::TemplateOnce; + let html = pool.tell_fortune().await?.render_once()?; + Ok(Html(html)) +} + +#[route("/queries", method = get)] +async fn queries( + Query(Num(num)): Query, + StateRef(pool): StateRef<'_, Pool>, +) -> HandleResult> { + pool.get_worlds(num).await.map(Json) +} + +#[route("/updates", method = get)] +async fn updates( + Query(Num(num)): Query, + StateRef(pool): StateRef<'_, Pool>, +) -> HandleResult> { + pool.update(num).await.map(Json) +} diff --git a/frameworks/Rust/xitca-web/src/ser.rs b/frameworks/Rust/xitca-web/src/ser.rs index 53dcff13cf0..3c630c54bc6 100644 --- a/frameworks/Rust/xitca-web/src/ser.rs +++ b/frameworks/Rust/xitca-web/src/ser.rs @@ -33,7 +33,7 @@ impl Message { pub struct Num(pub u16); -#[cfg_attr(feature = "pg-orm", derive(diesel::Queryable))] +#[cfg_attr(any(feature = "pg-orm", feature = "pg-orm-async"), derive(diesel::Queryable))] pub struct World { pub id: i32, pub randomnumber: i32, @@ -46,7 +46,7 @@ impl World { } } -#[cfg_attr(feature = "pg-orm", derive(diesel::Queryable))] +#[cfg_attr(any(feature = "pg-orm", feature = "pg-orm-async"), derive(diesel::Queryable))] pub struct Fortune { pub id: i32, pub message: Cow<'static, str>, @@ -62,16 +62,41 @@ impl Fortune { } } -// TODO: use another template engine with faster compile time.(preferably with no proc macro) -#[cfg_attr( - feature = "template", - derive(sailfish::TemplateOnce), - template(path = "fortune.stpl", rm_whitespace = true) -)] pub struct Fortunes { items: Vec, } +// this is roughly the code generated by sailfish::TemplateOnce macro. +// using the macro does not have any perf cost and this piece of code is expanded manually to speed up compile time of +// bench to reduce resource usage of bench runner +#[cfg(feature = "template")] +impl sailfish::TemplateOnce for Fortunes { + fn render_once(self) -> sailfish::RenderResult { + use sailfish::runtime::{Buffer, Render}; + + const PREFIX: &str = "\n\nFortunes\n\n\n\n"; + const SUFFIX: &str = "\n
    idmessage
    \n\n"; + + let mut buf = Buffer::with_capacity(1236); + + buf.push_str(PREFIX); + for item in self.items { + buf.push_str(""); + Render::render_escaped(&item.id, &mut buf)?; + buf.push_str(""); + Render::render_escaped(&item.message, &mut buf)?; + buf.push_str(""); + } + buf.push_str(SUFFIX); + + Ok(buf.into_string()) + } + + fn render_once_to(self, _: &mut sailfish::runtime::Buffer) -> Result<(), sailfish::runtime::RenderError> { + unimplemented!("") + } +} + impl Fortunes { #[inline] pub const fn new(items: Vec) -> Self { diff --git a/frameworks/Rust/xitca-web/src/util.rs b/frameworks/Rust/xitca-web/src/util.rs index 62888fb6c26..9183d067f5d 100755 --- a/frameworks/Rust/xitca-web/src/util.rs +++ b/frameworks/Rust/xitca-web/src/util.rs @@ -54,6 +54,15 @@ pub struct State { pub write_buf: RefCell, } +impl State { + pub fn new(client: DB) -> Self { + Self { + client, + write_buf: Default::default(), + } + } +} + #[cfg(not(target_arch = "wasm32"))] mod non_wasm { use rand::{rngs::SmallRng, Rng, SeedableRng}; @@ -72,37 +81,6 @@ mod non_wasm { self.0.gen_range(1..=10000) } } - - #[cfg(feature = "pg")] - mod pg_state { - use core::{cell::RefCell, future::Future, pin::Pin}; - - use xitca_http::{ - bytes::BytesMut, - util::middleware::context::{Context, ContextBuilder}, - }; - - use crate::{ - db::{self, Client}, - util::{HandleResult, State}, - }; - - pub type Ctx<'a, Req> = Context<'a, Req, State>; - - pub fn context_mw() -> ContextBuilder Pin>>>>> { - ContextBuilder::new(|| { - Box::pin(async { - db::create().await.map(|client| State { - client, - write_buf: RefCell::new(BytesMut::new()), - }) - }) as _ - }) - } - } - - #[cfg(feature = "pg")] - pub use pg_state::*; } #[cfg(not(target_arch = "wasm32"))] diff --git a/frameworks/Rust/xitca-web/xitca-web-axum.dockerfile b/frameworks/Rust/xitca-web/xitca-web-axum.dockerfile deleted file mode 100644 index 3c6271834ea..00000000000 --- a/frameworks/Rust/xitca-web/xitca-web-axum.dockerfile +++ /dev/null @@ -1,10 +0,0 @@ -FROM rust:1.81 - -ADD ./ /xitca-web -WORKDIR /xitca-web - -RUN cargo build --release --bin xitca-web-axum --features axum,io-uring,perf,pg-sync,template - -EXPOSE 8080 - -CMD ./target/release/xitca-web-axum diff --git a/frameworks/Rust/xitca-web/xitca-web-orm.dockerfile b/frameworks/Rust/xitca-web/xitca-web-orm.dockerfile new file mode 100644 index 00000000000..06e40825b00 --- /dev/null +++ b/frameworks/Rust/xitca-web/xitca-web-orm.dockerfile @@ -0,0 +1,10 @@ +FROM rust:1.81 + +ADD ./ /xitca-web +WORKDIR /xitca-web + +RUN cargo build --release --bin xitca-web-orm --features pg-orm-async,template,web-codegen + +EXPOSE 8080 + +CMD ./target/release/xitca-web-orm From eb5a28687fe3aa976d65c1550c6f2142b1443d0d Mon Sep 17 00:00:00 2001 From: fakeshadow <24548779@qq.com> Date: Tue, 15 Oct 2024 01:32:22 +0800 Subject: [PATCH 147/204] [xitca-web] new async runtime variant and header fix (#9322) * [xitca-web] reduce duplicate code and header fix * query parse fix * enable new variant of tokio runtime --- frameworks/Rust/xitca-web/.cargo/config.toml | 2 +- frameworks/Rust/xitca-web/Cargo.lock | 106 +++++++-------- frameworks/Rust/xitca-web/Cargo.toml | 24 ++-- .../Rust/xitca-web/benchmark_config.json | 4 +- frameworks/Rust/xitca-web/src/db.rs | 33 +++-- frameworks/Rust/xitca-web/src/db_diesel.rs | 76 ++++------- .../Rust/xitca-web/src/db_diesel_async.rs | 101 +++++---------- .../Rust/xitca-web/src/db_unrealistic.rs | 37 +++--- frameworks/Rust/xitca-web/src/db_util.rs | 121 ++++++++++++------ .../src/{main_iou.rs => main_unrealistic.rs} | 98 +++++++------- frameworks/Rust/xitca-web/src/ser.rs | 4 +- frameworks/Rust/xitca-web/src/util.rs | 32 +---- .../Rust/xitca-web/xitca-web-iou.dockerfile | 10 -- .../xitca-web-unrealistic.dockerfile | 10 ++ 14 files changed, 314 insertions(+), 344 deletions(-) rename frameworks/Rust/xitca-web/src/{main_iou.rs => main_unrealistic.rs} (60%) delete mode 100644 frameworks/Rust/xitca-web/xitca-web-iou.dockerfile create mode 100644 frameworks/Rust/xitca-web/xitca-web-unrealistic.dockerfile diff --git a/frameworks/Rust/xitca-web/.cargo/config.toml b/frameworks/Rust/xitca-web/.cargo/config.toml index 7d3c09f8a1a..df736010a76 100644 --- a/frameworks/Rust/xitca-web/.cargo/config.toml +++ b/frameworks/Rust/xitca-web/.cargo/config.toml @@ -1,5 +1,5 @@ [build] -rustflags = ["-C", "target-cpu=native"] +rustflags = ["-C", "target-cpu=native", "--cfg", "tokio_unstable"] incremental = false [target.wasm32-wasip1-threads] diff --git a/frameworks/Rust/xitca-web/Cargo.lock b/frameworks/Rust/xitca-web/Cargo.lock index 71038073ca5..070a2e67550 100644 --- a/frameworks/Rust/xitca-web/Cargo.lock +++ b/frameworks/Rust/xitca-web/Cargo.lock @@ -117,9 +117,9 @@ checksum = "428d9aa8fbc0670b7b8d6030a7fadd0f86151cae55e4dbbece15f3780a3dfaf3" [[package]] name = "cc" -version = "1.1.24" +version = "1.1.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "812acba72f0a070b003d3697490d2b55b837230ae7c6c6497f05cc2ddbb8d938" +checksum = "b16803a61b81d9eabb7eae2588776c4c1e584b738ede45fdbb4c972cec1e9945" dependencies = [ "shlex", ] @@ -288,9 +288,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" +checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" dependencies = [ "futures-core", "futures-sink", @@ -298,15 +298,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" +checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" [[package]] name = "futures-macro" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" +checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", @@ -315,21 +315,21 @@ dependencies = [ [[package]] name = "futures-sink" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" +checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" [[package]] name = "futures-task" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" +checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" [[package]] name = "futures-util" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" +checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" dependencies = [ "futures-core", "futures-macro", @@ -441,9 +441,9 @@ checksum = "9028f49264629065d057f340a86acb84867925865f73bbf8d47b4d149a7e88b8" [[package]] name = "js-sys" -version = "0.3.70" +version = "0.3.72" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1868808506b929d7b0cfa8f75951347aa71bb21144b7791bae35d9bccfcfe37a" +checksum = "6a88f1bda2bd75b0452a14784937d796722fdebfe50df998aeb3f0b7603019a9" dependencies = [ "wasm-bindgen", ] @@ -545,12 +545,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.20.1" +version = "1.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82881c4be219ab5faaf2ad5e5e5ecdff8c66bd7402ca3160975c93b24961afd1" -dependencies = [ - "portable-atomic", -] +checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" [[package]] name = "parking_lot" @@ -611,12 +608,6 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" -[[package]] -name = "portable-atomic" -version = "1.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc9c68a3f6da06753e9335d63e27f6b9754dd1920d941135b7ea8224f141adb2" - [[package]] name = "postgres-protocol" version = "0.6.7" @@ -666,9 +657,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.86" +version = "1.0.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" +checksum = "b3e4daa0dcf6feba26f985457cdf104d4b4256fc5a09547140f3631bb076b19a" dependencies = [ "unicode-ident", ] @@ -943,8 +934,7 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" version = "1.40.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2b070231665d27ad9ec9b8df639893f46727666c6767db40317fbe920a5d998" +source = "git+https://github.com/tokio-rs/tokio.git?rev=512e9de#512e9decfb683d22f4a145459142542caa0894c9" dependencies = [ "backtrace", "bytes", @@ -1086,9 +1076,9 @@ checksum = "b8dad83b4f25e74f184f64c43b150b91efe7647395b42289f38e50566d82855b" [[package]] name = "wasm-bindgen" -version = "0.2.93" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a82edfc16a6c469f5f44dc7b571814045d60404b55a0ee849f9bcfa2e63dd9b5" +checksum = "128d1e363af62632b8eb57219c8fd7877144af57558fb2ef0368d0087bddeb2e" dependencies = [ "cfg-if", "once_cell", @@ -1097,9 +1087,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.93" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9de396da306523044d3302746f1208fa71d7532227f15e347e2d93e4145dd77b" +checksum = "cb6dd4d3ca0ddffd1dd1c9c04f94b868c37ff5fac97c30b97cff2d74fce3a358" dependencies = [ "bumpalo", "log", @@ -1112,9 +1102,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.93" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "585c4c91a46b072c92e908d99cb1dcdf95c5218eeb6f3bf1efa991ee7a68cccf" +checksum = "e79384be7f8f5a9dd5d7167216f022090cf1f9ec128e6e6a482a2cb5c5422c56" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -1122,9 +1112,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.93" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836" +checksum = "26c6ab57572f7a24a4985830b120de1594465e5d500f24afe89e16b4e833ef68" dependencies = [ "proc-macro2", "quote", @@ -1135,15 +1125,15 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.93" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c62a0a307cb4a311d3a07867860911ca130c3494e8c2719593806c08bc5d0484" +checksum = "65fc09f10666a9f147042251e0dda9c18f166ff7de300607007e96bdebc1068d" [[package]] name = "web-sys" -version = "0.3.70" +version = "0.3.72" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26fdeaafd9bd129f65e7c031593c24d62186301e0c72c8978fa1678be7d532c0" +checksum = "f6488b90108c040df0fe62fa815cbdee25124641df01814dd7282749234c6112" dependencies = [ "js-sys", "wasm-bindgen", @@ -1258,7 +1248,7 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "xitca-codegen" version = "0.4.0" -source = "git+http://github.com/HFQR/xitca-web?rev=d3066ba#d3066ba5fc65e89c8a20890dd529f05818c853d6" +source = "git+http://github.com/HFQR/xitca-web?rev=1de8d9c#1de8d9c079e73f7fd9ba953741302d87e50d831a" dependencies = [ "quote", "syn", @@ -1267,7 +1257,7 @@ dependencies = [ [[package]] name = "xitca-http" version = "0.7.0" -source = "git+http://github.com/HFQR/xitca-web?rev=d3066ba#d3066ba5fc65e89c8a20890dd529f05818c853d6" +source = "git+http://github.com/HFQR/xitca-web?rev=1de8d9c#1de8d9c079e73f7fd9ba953741302d87e50d831a" dependencies = [ "futures-core", "http", @@ -1314,6 +1304,22 @@ dependencies = [ "xitca-unsafe-collection", ] +[[package]] +name = "xitca-postgres" +version = "0.3.0" +source = "git+http://github.com/HFQR/xitca-web?rev=1de8d9c#1de8d9c079e73f7fd9ba953741302d87e50d831a" +dependencies = [ + "fallible-iterator", + "futures-core", + "percent-encoding", + "postgres-protocol", + "postgres-types", + "tokio", + "tracing", + "xitca-io", + "xitca-unsafe-collection", +] + [[package]] name = "xitca-postgres-diesel" version = "0.1.0" @@ -1324,7 +1330,7 @@ dependencies = [ "futures-core", "scoped-futures", "tokio", - "xitca-postgres", + "xitca-postgres 0.2.1", ] [[package]] @@ -1339,7 +1345,7 @@ dependencies = [ [[package]] name = "xitca-server" version = "0.5.0" -source = "git+http://github.com/HFQR/xitca-web?rev=d3066ba#d3066ba5fc65e89c8a20890dd529f05818c853d6" +source = "git+http://github.com/HFQR/xitca-web?rev=1de8d9c#1de8d9c079e73f7fd9ba953741302d87e50d831a" dependencies = [ "socket2 0.5.7", "tokio", @@ -1353,7 +1359,7 @@ dependencies = [ [[package]] name = "xitca-service" version = "0.3.0" -source = "git+http://github.com/HFQR/xitca-web?rev=d3066ba#d3066ba5fc65e89c8a20890dd529f05818c853d6" +source = "git+http://github.com/HFQR/xitca-web?rev=1de8d9c#1de8d9c079e73f7fd9ba953741302d87e50d831a" [[package]] name = "xitca-unsafe-collection" @@ -1383,7 +1389,7 @@ dependencies = [ "tokio-uring", "xitca-http", "xitca-io", - "xitca-postgres", + "xitca-postgres 0.3.0", "xitca-postgres-diesel", "xitca-server", "xitca-service", @@ -1394,7 +1400,7 @@ dependencies = [ [[package]] name = "xitca-web" version = "0.7.0" -source = "git+http://github.com/HFQR/xitca-web?rev=d3066ba#d3066ba5fc65e89c8a20890dd529f05818c853d6" +source = "git+http://github.com/HFQR/xitca-web?rev=1de8d9c#1de8d9c079e73f7fd9ba953741302d87e50d831a" dependencies = [ "futures-core", "pin-project-lite", diff --git a/frameworks/Rust/xitca-web/Cargo.toml b/frameworks/Rust/xitca-web/Cargo.toml index 03d7098e796..c547c16de48 100644 --- a/frameworks/Rust/xitca-web/Cargo.toml +++ b/frameworks/Rust/xitca-web/Cargo.toml @@ -9,9 +9,9 @@ path = "./src/main.rs" required-features = ["io-uring", "pg", "router", "template"] [[bin]] -name = "xitca-web-iou" -path = "./src/main_iou.rs" -required-features = ["io-uring", "perf", "pg", "template"] +name = "xitca-web-unrealistic" +path = "./src/main_unrealistic.rs" +required-features = ["perf", "pg", "template"] [[bin]] name = "xitca-web-wasm" @@ -34,7 +34,7 @@ pg = ["dep:xitca-postgres"] # diesel orm optional pg-orm = ["diesel/r2d2"] # diesel async orm optional -pg-orm-async = ["dep:diesel", "dep:diesel-async", "dep:xitca-postgres-diesel", "futures-util"] +pg-orm-async = ["dep:diesel", "dep:diesel-async", "dep:xitca-postgres-diesel", "dep:futures-util"] # http router optional router = ["xitca-http/router"] # web optional @@ -64,7 +64,7 @@ serde_json = { version = "1" } xitca-web = { version = "0.7", features = ["json"], optional = true } # raw-pg optional -xitca-postgres = { version = "0.2", optional = true } +xitca-postgres = { version = "0.3", optional = true } # orm optional diesel = { version = "2", features = ["postgres"], optional = true } @@ -100,9 +100,11 @@ xitca-postgres-diesel = { git = "https://github.com/fakeshadow/xitca-postgres-di diesel-async = { git = "https://github.com/weiznich/diesel_async", rev = "5b8262b" } mio = { git = "https://github.com/fakeshadow/mio", rev = "9bae6012b7ecfc6083350785f71a5e8265358178" } - -xitca-codegen = { git = "http://github.com/HFQR/xitca-web", rev = "d3066ba" } -xitca-http = { git = "http://github.com/HFQR/xitca-web", rev = "d3066ba" } -xitca-server = { git = "http://github.com/HFQR/xitca-web", rev = "d3066ba" } -xitca-service = { git = "http://github.com/HFQR/xitca-web", rev = "d3066ba" } -xitca-web = { git = "http://github.com/HFQR/xitca-web", rev = "d3066ba" } +tokio = { git = "https://github.com/tokio-rs/tokio.git", rev = "512e9de" } + +xitca-codegen = { git = "http://github.com/HFQR/xitca-web", rev = "1de8d9c" } +xitca-http = { git = "http://github.com/HFQR/xitca-web", rev = "1de8d9c" } +xitca-postgres = { git = "http://github.com/HFQR/xitca-web", rev = "1de8d9c" } +xitca-server = { git = "http://github.com/HFQR/xitca-web", rev = "1de8d9c" } +xitca-service = { git = "http://github.com/HFQR/xitca-web", rev = "1de8d9c" } +xitca-web = { git = "http://github.com/HFQR/xitca-web", rev = "1de8d9c" } diff --git a/frameworks/Rust/xitca-web/benchmark_config.json b/frameworks/Rust/xitca-web/benchmark_config.json index 973d1961472..db81e362742 100755 --- a/frameworks/Rust/xitca-web/benchmark_config.json +++ b/frameworks/Rust/xitca-web/benchmark_config.json @@ -24,7 +24,7 @@ "notes": "", "versus": "" }, - "iou": { + "unrealistic": { "json_url": "/json", "plaintext_url": "/plaintext", "db_url": "/db", @@ -42,7 +42,7 @@ "webserver": "xitca-server", "os": "Linux", "database_os": "Linux", - "display_name": "xitca-web [iou]", + "display_name": "xitca-web [unrealistic]", "notes": "", "versus": "" }, diff --git a/frameworks/Rust/xitca-web/src/db.rs b/frameworks/Rust/xitca-web/src/db.rs index ad75d6f8bbe..abb9ef10870 100644 --- a/frameworks/Rust/xitca-web/src/db.rs +++ b/frameworks/Rust/xitca-web/src/db.rs @@ -1,18 +1,16 @@ #[path = "./db_util.rs"] mod db_util; -use std::cell::RefCell; +use core::cell::RefCell; -use xitca_postgres::{ - iter::AsyncLendingIterator, pipeline::Pipeline, pool::Pool, statement::Statement, Execute, ExecuteMut, -}; +use xitca_postgres::{iter::AsyncLendingIterator, pipeline::Pipeline, pool::Pool, statement::Statement, Execute}; use super::{ ser::{Fortune, Fortunes, World}, util::{HandleResult, DB_URL}, }; -use db_util::{sort_update_params, update_query, Shared, FORTUNE_STMT, WORLD_STMT}; +use db_util::{not_found, sort_update_params, update_query_from_num, Shared, FORTUNE_STMT, WORLD_STMT}; pub struct Client { pool: Pool, @@ -25,7 +23,7 @@ pub async fn create() -> HandleResult { pool: Pool::builder(DB_URL).capacity(1).build()?, shared: Default::default(), updates: core::iter::once(Box::from("")) - .chain((1..=500).map(update_query)) + .chain((1..=500).map(update_query_from_num)) .collect(), }) } @@ -33,10 +31,10 @@ pub async fn create() -> HandleResult { impl Client { pub async fn get_world(&self) -> HandleResult { let mut conn = self.pool.get().await?; - let stmt = WORLD_STMT.execute_mut(&mut conn).await?; + let stmt = WORLD_STMT.execute(&mut conn).await?; let id = self.shared.borrow_mut().0.gen_id(); let mut res = stmt.bind([id]).query(&conn.consume()).await?; - let row = res.try_next().await?.ok_or("request World does not exist")?; + let row = res.try_next().await?.ok_or_else(not_found)?; Ok(World::new(row.get(0), row.get(1))) } @@ -44,21 +42,20 @@ impl Client { let len = num as usize; let mut conn = self.pool.get().await?; - let stmt = WORLD_STMT.execute_mut(&mut conn).await?; + let stmt = WORLD_STMT.execute(&mut conn).await?; let mut res = { let (ref mut rng, ref mut buf) = *self.shared.borrow_mut(); let mut pipe = Pipeline::with_capacity_from_buf(len, buf); - (0..num).try_for_each(|_| stmt.bind([rng.gen_id()]).query_mut(&mut pipe))?; + (0..num).try_for_each(|_| stmt.bind([rng.gen_id()]).query(&mut pipe))?; pipe.query(&conn.consume())? }; let mut worlds = Vec::with_capacity(len); while let Some(mut item) = res.try_next().await? { - while let Some(row) = item.try_next().await? { - worlds.push(World::new(row.get(0), row.get(1))) - } + let row = item.try_next().await?.ok_or_else(not_found)?; + worlds.push(World::new(row.get(0), row.get(1))); } Ok(worlds) @@ -69,8 +66,8 @@ impl Client { let update = self.updates.get(len).ok_or("request num is out of range")?; let mut conn = self.pool.get().await?; - let world_stmt = WORLD_STMT.execute_mut(&mut conn).await?; - let update_stmt = Statement::named(update, &[]).execute_mut(&mut conn).await?; + let world_stmt = WORLD_STMT.execute(&mut conn).await?; + let update_stmt = Statement::named(update, &[]).execute(&mut conn).await?; let mut params = Vec::with_capacity(len); @@ -81,9 +78,9 @@ impl Client { let w_id = rng.gen_id(); let r_id = rng.gen_id(); params.push([w_id, r_id]); - world_stmt.bind([w_id]).query_mut(&mut pipe) + world_stmt.bind([w_id]).query(&mut pipe) })?; - update_stmt.bind(sort_update_params(¶ms)).query_mut(&mut pipe)?; + update_stmt.bind(sort_update_params(¶ms)).query(&mut pipe)?; pipe.query(&conn.consume())? }; @@ -106,7 +103,7 @@ impl Client { items.push(Fortune::new(0, "Additional fortune added at request time.")); let mut conn = self.pool.get().await?; - let stmt = FORTUNE_STMT.execute_mut(&mut conn).await?; + let stmt = FORTUNE_STMT.execute(&mut conn).await?; let mut res = stmt.query(&conn.consume()).await?; while let Some(row) = res.try_next().await? { diff --git a/frameworks/Rust/xitca-web/src/db_diesel.rs b/frameworks/Rust/xitca-web/src/db_diesel.rs index cf19768ac9f..1675a7c2cd1 100644 --- a/frameworks/Rust/xitca-web/src/db_diesel.rs +++ b/frameworks/Rust/xitca-web/src/db_diesel.rs @@ -1,3 +1,6 @@ +#[path = "./db_util.rs"] +mod db_util; + use std::{ io, sync::{Arc, Mutex}, @@ -7,9 +10,11 @@ use diesel::{prelude::*, r2d2}; use crate::{ ser::{Fortune, Fortunes, World}, - util::{bulk_update_gen, Error, HandleResult, Rand, DB_URL}, + util::{HandleResult, Rand, DB_URL}, }; +use db_util::{not_found, update_query_from_ids}; + pub type Pool = Arc<_Pool>; pub struct _Pool { @@ -34,12 +39,6 @@ pub fn create() -> io::Result> { }) } -#[cold] -#[inline(never)] -fn not_found() -> Error { - "world not found".into() -} - impl _Pool { pub fn get_world(&self) -> HandleResult { use crate::schema::world::dsl::*; @@ -53,16 +52,12 @@ impl _Pool { use crate::schema::world::dsl::*; let mut conn = self.pool.get()?; - (0..num) - .map(|_| { - let w_id = self.rng.lock().unwrap().gen_id(); - world - .filter(id.eq(w_id)) - .load::(&mut conn)? - .pop() - .ok_or_else(not_found) - }) - .collect() + core::iter::repeat_with(|| { + let w_id = self.rng.lock().unwrap().gen_id(); + world.filter(id.eq(w_id)).load(&mut conn)?.pop().ok_or_else(not_found) + }) + .take(num as _) + .collect() } pub fn update(&self, num: u16) -> HandleResult> { @@ -75,30 +70,20 @@ impl _Pool { rngs.sort_by(|(a, _), (b, _)| a.cmp(b)); - let mut worlds = { - let mut conn = self.pool.get()?; + let update_sql = update_query_from_ids(&rngs); - let worlds = rngs - .iter() - .map(|(w_id, num)| { - world - .filter(id.eq(w_id)) - .load::(&mut conn)? - .pop() - .map(|mut w| { - w.randomnumber = *num; - w - }) - .ok_or_else(not_found) - }) - .collect::>>()?; - - diesel::sql_query(update_query(&rngs)).execute(&mut conn)?; - - worlds - }; + let mut conn = self.pool.get()?; + + let worlds = rngs + .into_iter() + .map(|(w_id, num)| { + let mut w: World = world.filter(id.eq(w_id)).load(&mut conn)?.pop().ok_or_else(not_found)?; + w.randomnumber = num; + Ok(w) + }) + .collect::>>()?; - worlds.sort_by_key(|w| w.id); + diesel::sql_query(update_sql).execute(&mut conn)?; Ok(worlds) } @@ -108,7 +93,7 @@ impl _Pool { let mut items = { let mut conn = self.pool.get()?; - fortune.load::(&mut conn)? + fortune.load(&mut conn)? }; items.push(Fortune::new(0, "Additional fortune added at request time.")); @@ -117,14 +102,3 @@ impl _Pool { Ok(Fortunes::new(items)) } } - -// diesel does not support high level bulk update api. use raw sql to bypass the limitation. -// relate discussion: https://github.com/diesel-rs/diesel/discussions/2879 -fn update_query(ids: &[(i32, i32)]) -> String { - bulk_update_gen(|query| { - use std::fmt::Write; - ids.iter().for_each(|(w_id, num)| { - write!(query, "({}::int,{}::int),", w_id, num).unwrap(); - }); - }) -} diff --git a/frameworks/Rust/xitca-web/src/db_diesel_async.rs b/frameworks/Rust/xitca-web/src/db_diesel_async.rs index fdd93e43a74..e3ee7e895fd 100644 --- a/frameworks/Rust/xitca-web/src/db_diesel_async.rs +++ b/frameworks/Rust/xitca-web/src/db_diesel_async.rs @@ -1,7 +1,7 @@ -use std::{ - io, - sync::{Arc, Mutex}, -}; +#[path = "./db_util.rs"] +mod db_util; + +use std::{io, sync::Mutex}; use diesel::prelude::*; use diesel_async::{ @@ -16,17 +16,17 @@ use xitca_postgres_diesel::AsyncPgConnection; use crate::{ ser::{Fortune, Fortunes, World}, - util::{bulk_update_gen, Error, HandleResult, Rand, DB_URL}, + util::{HandleResult, Rand, DB_URL}, }; -pub type Pool = Arc<_Pool>; +use db_util::{not_found, update_query_from_ids}; -pub struct _Pool { +pub struct Pool { pool: bb8::Pool, rng: Mutex, } -pub async fn create() -> io::Result> { +pub async fn create() -> io::Result { bb8::Pool::builder() .max_size(1) .min_idle(Some(1)) @@ -34,21 +34,13 @@ pub async fn create() -> io::Result> { .build(AsyncDieselConnectionManager::new(DB_URL)) .await .map_err(io::Error::other) - .map(|pool| { - Arc::new(_Pool { - pool, - rng: Mutex::new(Rand::default()), - }) + .map(|pool| Pool { + pool, + rng: Mutex::new(Rand::default()), }) } -#[cold] -#[inline(never)] -fn not_found() -> Error { - "world not found".into() -} - -impl _Pool { +impl Pool { pub async fn get_world(&self) -> HandleResult { use crate::schema::world::dsl::*; { @@ -66,13 +58,13 @@ impl _Pool { { let mut conn = self.pool.get().await?; let mut rng = self.rng.lock().unwrap(); - (0..num) - .map(|_| { - let w_id = rng.gen_id(); - let fut = world.filter(id.eq(w_id)).load::(&mut conn); - async { fut.await?.pop().ok_or_else(not_found) } - }) - .collect::>() + core::iter::repeat_with(|| { + let w_id = rng.gen_id(); + let fut = world.filter(id.eq(w_id)).load(&mut conn); + async { fut.await?.pop().ok_or_else(not_found) } + }) + .take(num as _) + .collect::>() } .try_collect() .await @@ -81,48 +73,36 @@ impl _Pool { pub async fn update(&self, num: u16) -> HandleResult> { use crate::schema::world::dsl::*; - let mut rngs = Vec::with_capacity(num as _); - let (select_res, update_res) = { let mut conn = self.pool.get().await?; - let mut rng = self.rng.lock().unwrap(); - let select = (0..num) - .map(|_| { - let w_id = rng.gen_id(); - let num = rng.gen_id(); - - rngs.push((w_id, num)); + let (select, mut rngs) = core::iter::repeat_with(|| { + let w_id = rng.gen_id(); + let num = rng.gen_id(); - let fut = world.filter(id.eq(w_id)).load::(&mut conn); + let fut = world.filter(id.eq(w_id)).load::(&mut conn); + let select = async move { + let mut w = fut.await?.pop().ok_or_else(not_found)?; + w.randomnumber = num; + HandleResult::Ok(w) + }; - async move { - fut.await? - .pop() - .map(|mut w| { - w.randomnumber = num; - w - }) - .ok_or_else(not_found) - } - }) - .collect::>(); + (select, (w_id, num)) + }) + .take(num as _) + .collect::<(FuturesUnordered<_>, Vec<_>)>(); rngs.sort_by(|(a, _), (b, _)| a.cmp(b)); - let update = diesel::sql_query(update_query(&rngs)).execute(&mut conn); + let update = diesel::sql_query(update_query_from_ids(&rngs)).execute(&mut conn); join(select.try_collect::>(), update) } .await; update_res?; - let mut worlds = select_res?; - - worlds.sort_by_key(|w| w.id); - - Ok(worlds) + select_res } pub async fn tell_fortune(&self) -> HandleResult { @@ -130,7 +110,7 @@ impl _Pool { let mut items = { let mut conn = self.pool.get().await?; - fortune.load::(&mut conn) + fortune.load(&mut conn) } .await?; @@ -140,14 +120,3 @@ impl _Pool { Ok(Fortunes::new(items)) } } - -// diesel does not support high level bulk update api. use raw sql to bypass the limitation. -// relate discussion: https://github.com/diesel-rs/diesel/discussions/2879 -fn update_query(ids: &[(i32, i32)]) -> String { - bulk_update_gen(|query| { - use std::fmt::Write; - ids.iter().for_each(|(w_id, num)| { - write!(query, "({}::int,{}::int),", w_id, num).unwrap(); - }); - }) -} diff --git a/frameworks/Rust/xitca-web/src/db_unrealistic.rs b/frameworks/Rust/xitca-web/src/db_unrealistic.rs index 7b04449a716..99e4249e39b 100644 --- a/frameworks/Rust/xitca-web/src/db_unrealistic.rs +++ b/frameworks/Rust/xitca-web/src/db_unrealistic.rs @@ -6,14 +6,14 @@ mod db_util; use std::cell::RefCell; -use xitca_postgres::{iter::AsyncLendingIterator, pipeline::Pipeline, statement::Statement, Execute, ExecuteMut}; +use xitca_postgres::{iter::AsyncLendingIterator, pipeline::Pipeline, statement::Statement, Execute}; use super::{ ser::{Fortune, Fortunes, World}, util::{HandleResult, DB_URL}, }; -use db_util::{sort_update_params, update_query, Shared, FORTUNE_STMT, WORLD_STMT}; +use db_util::{not_found, sort_update_params, update_query_from_num, Shared, FORTUNE_STMT, WORLD_STMT}; pub struct Client { cli: xitca_postgres::Client, @@ -36,7 +36,7 @@ pub async fn create() -> HandleResult { let mut updates = vec![Statement::default()]; - for update in (1..=500).map(update_query).into_iter() { + for update in (1..=500).map(update_query_from_num).into_iter() { let stmt = Statement::named(&update, &[]).execute(&cli).await?.leak(); updates.push(stmt); } @@ -54,26 +54,28 @@ impl Client { pub async fn get_world(&self) -> HandleResult { let id = self.shared.borrow_mut().0.gen_id(); let mut res = self.world.bind([id]).query(&self.cli).await?; - let row = res.try_next().await?.ok_or("request World does not exist")?; + let row = res.try_next().await?.ok_or_else(not_found)?; Ok(World::new(row.get(0), row.get(1))) } pub async fn get_worlds(&self, num: u16) -> HandleResult> { let len = num as usize; - let mut res = { - let (ref mut rng, ref mut buf) = *self.shared.borrow_mut(); - let mut pipe = Pipeline::with_capacity_from_buf(len, buf); - (0..num).try_for_each(|_| self.world.bind([rng.gen_id()]).query_mut(&mut pipe))?; - pipe.query(&self.cli)? + let mut res = Vec::with_capacity(len); + + { + let (ref mut rng, ..) = *self.shared.borrow_mut(); + for _ in 0..len { + let stream = self.world.bind([rng.gen_id()]).query(&self.cli).await?; + res.push(stream); + } }; let mut worlds = Vec::with_capacity(len); - while let Some(mut item) = res.try_next().await? { - while let Some(row) = item.try_next().await? { - worlds.push(World::new(row.get(0), row.get(1))) - } + for mut stream in res { + let row = stream.try_next().await?.ok_or_else(not_found)?; + worlds.push(World::new(row.get(0), row.get(1))); } Ok(worlds) @@ -86,16 +88,15 @@ impl Client { let mut res = { let (ref mut rng, ref mut buf) = *self.shared.borrow_mut(); - let mut pipe = Pipeline::with_capacity_from_buf(len + 1, buf); + // unrealistic as all queries are sent with only one sync point. + let mut pipe = Pipeline::unsync_with_capacity_from_buf(len + 1, buf); (0..num).try_for_each(|_| { let w_id = rng.gen_id(); let r_id = rng.gen_id(); params.push([w_id, r_id]); - self.world.bind([w_id]).query_mut(&mut pipe) + self.world.bind([w_id]).query(&mut pipe) })?; - self.updates[len] - .bind(sort_update_params(¶ms)) - .query_mut(&mut pipe)?; + self.updates[len].bind(sort_update_params(¶ms)).query(&mut pipe)?; pipe.query(&self.cli)? }; diff --git a/frameworks/Rust/xitca-web/src/db_util.rs b/frameworks/Rust/xitca-web/src/db_util.rs index 19879333427..42c2c455bbe 100644 --- a/frameworks/Rust/xitca-web/src/db_util.rs +++ b/frameworks/Rust/xitca-web/src/db_util.rs @@ -1,53 +1,96 @@ -use xitca_io::bytes::BytesMut; -use xitca_postgres::{ - statement::{Statement, StatementNamed}, - types::Type, -}; +use crate::util::Error; -use crate::util::{bulk_update_gen, Rand}; +#[cfg(any(feature = "pg-orm", feature = "pg-orm-async"))] +// diesel does not support high level bulk update api. use raw sql to bypass the limitation. +// relate discussion: https://github.com/diesel-rs/diesel/discussions/2879 +pub fn update_query_from_ids(ids: &[(i32, i32)]) -> String { + update_query(|query| { + use core::fmt::Write; + ids.iter().for_each(|(w_id, num)| { + write!(query, "({}::int,{}::int),", w_id, num).unwrap(); + }); + }) +} -pub(super) type Shared = (Rand, BytesMut); +fn update_query(func: impl FnOnce(&mut String)) -> String { + const PREFIX: &str = "UPDATE world SET randomNumber = w.r FROM (VALUES "; + const SUFFIX: &str = ") AS w (i,r) WHERE world.id = w.i"; -pub(super) const FORTUNE_STMT: StatementNamed = Statement::named("SELECT * FROM fortune", &[]); -pub(super) const WORLD_STMT: StatementNamed = Statement::named("SELECT * FROM world WHERE id=$1", &[Type::INT4]); + let mut query = String::from(PREFIX); -pub(super) fn update_query(num: usize) -> Box { - bulk_update_gen(|query| { - use std::fmt::Write; - (1..=num).fold((1, query), |(idx, query), _| { - write!(query, "(${}::int,${}::int),", idx, idx + 1).unwrap(); - (idx + 2, query) - }); - }) - .into_boxed_str() + func(&mut query); + + if query.ends_with(',') { + query.pop(); + } + + query.push_str(SUFFIX); + + query } -pub(super) fn sort_update_params(params: &[[i32; 2]]) -> impl ExactSizeIterator { - let mut params = params.to_owned(); - params.sort_by(|a, b| a[0].cmp(&b[0])); +#[cold] +#[inline(never)] +pub fn not_found() -> Error { + "request World does not exist".into() +} - struct ParamIter(I); +#[cfg(feature = "pg")] +pub use pg::*; - impl Iterator for ParamIter - where - I: Iterator, - { - type Item = I::Item; +#[cfg(feature = "pg")] +pub mod pg { + use xitca_io::bytes::BytesMut; + use xitca_postgres::{ + statement::{Statement, StatementNamed}, + types::Type, + }; - #[inline] - fn next(&mut self) -> Option { - self.0.next() - } + use crate::util::Rand; - #[inline] - fn size_hint(&self) -> (usize, Option) { - self.0.size_hint() - } + pub type Shared = (Rand, BytesMut); + + pub const FORTUNE_STMT: StatementNamed = Statement::named("SELECT * FROM fortune", &[]); + pub const WORLD_STMT: StatementNamed = Statement::named("SELECT * FROM world WHERE id=$1", &[Type::INT4]); + + pub fn update_query_from_num(num: usize) -> Box { + super::update_query(|query| { + use core::fmt::Write; + (1..=num).fold(1, |idx, _| { + write!(query, "(${}::int,${}::int),", idx, idx + 1).unwrap(); + idx + 2 + }); + }) + .into_boxed_str() } - // impl depends on compiler optimization to flat Vec<[T]> to Vec when inferring - // it's size hint. possible to cause runtime panic. - impl ExactSizeIterator for ParamIter where I: Iterator {} + pub fn sort_update_params(params: &[[i32; 2]]) -> impl ExactSizeIterator { + let mut params = params.to_owned(); + params.sort_by(|a, b| a[0].cmp(&b[0])); + + struct ParamIter(I); + + impl Iterator for ParamIter + where + I: Iterator, + { + type Item = I::Item; - ParamIter(params.into_iter().flatten()) + #[inline] + fn next(&mut self) -> Option { + self.0.next() + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.0.size_hint() + } + } + + // impl depends on compiler optimization to flat Vec<[T]> to Vec when inferring + // it's size hint. possible to cause runtime panic. + impl ExactSizeIterator for ParamIter where I: Iterator {} + + ParamIter(params.into_iter().flatten()) + } } diff --git a/frameworks/Rust/xitca-web/src/main_iou.rs b/frameworks/Rust/xitca-web/src/main_unrealistic.rs similarity index 60% rename from frameworks/Rust/xitca-web/src/main_iou.rs rename to frameworks/Rust/xitca-web/src/main_unrealistic.rs index 7dcf6d1a719..e291799408c 100644 --- a/frameworks/Rust/xitca-web/src/main_iou.rs +++ b/frameworks/Rust/xitca-web/src/main_unrealistic.rs @@ -1,5 +1,4 @@ -// reference of if/how moving from epoll to io-uring(or mixture of the two) make sense for network io. -// with comment on explaining why some practice are unrealistic +// unrealistic bench showcase popular tricks for boosting bench score artificially // custom global memory allocator don't affect real world performance in noticeable amount. // in real world they should be used for reason like security, debug/profiling capability etc. @@ -15,13 +14,16 @@ use std::{convert::Infallible, io}; use xitca_http::{ bytes::BufMutWriter, - h1::dispatcher_uring_unreal::{Dispatcher, Request, Response}, + h1::dispatcher_unreal::{Dispatcher, Request, Response}, http::StatusCode, }; -use xitca_io::net::io_uring::TcpStream; +use xitca_io::net::TcpStream; use xitca_service::Service; -use self::{ser::Message, util::State}; +use self::{ + ser::Message, + util::{QueryParse, State}, +}; fn main() -> io::Result<()> { let addr = "0.0.0.0:8080".parse().unwrap(); @@ -30,36 +32,40 @@ fn main() -> io::Result<()> { let handle = core::iter::repeat_with(|| { std::thread::spawn(move || { - tokio_uring::start(async { - let socket = tokio::net::TcpSocket::new_v4()?; - socket.set_reuseaddr(true)?; - // unrealistic due to following reason: - // 1. this only works good on unix system. - // 2. no resource distribution adjustment between sockets on different threads. causing uneven workload - // where some threads are idle while others busy. resulting in overall increased latency - socket.set_reuseport(true)?; - socket.bind(addr)?; - let listener = socket.listen(1024)?; - - let client = db::create().await.unwrap(); - - // unrealistic http dispatcher. no spec check. no security feature. - let service = Dispatcher::new(handler, State::new(client)); - - loop { - match listener.accept().await { - Ok((stream, _)) => { - let stream = stream.into_std()?; - let stream = TcpStream::from_std(stream); - let service = service.clone(); - tokio::task::spawn_local(async move { - let _ = service.call(stream).await; - }); - } - Err(e) => return Err(e), - }; - } - }) + tokio::runtime::Builder::new_current_thread() + .enable_all() + .build_local(&Default::default()) + .unwrap() + .block_on(async { + let socket = tokio::net::TcpSocket::new_v4()?; + socket.set_reuseaddr(true)?; + // unrealistic due to following reason: + // 1. this only works good on unix system. + // 2. no resource distribution adjustment between sockets on different threads. causing uneven workload + // where some threads are idle while others busy. resulting in overall increased latency + socket.set_reuseport(true)?; + socket.bind(addr)?; + let listener = socket.listen(1024)?; + + let client = db::create().await.unwrap(); + + // unrealistic http dispatcher. no spec check. no security feature. + let service = Dispatcher::new(handler, State::new(client)); + + loop { + match listener.accept().await { + Ok((stream, _)) => { + let stream = stream.into_std()?; + let stream = TcpStream::from_std(stream)?; + let service = service.clone(); + tokio::task::spawn_local(async move { + let _ = service.call(stream).await; + }); + } + Err(e) => return Err(e), + }; + } + }) }) }) .take(cores) @@ -74,9 +80,9 @@ fn main() -> io::Result<()> { Ok(()) } -async fn handler<'h>(req: Request<'h, '_>, res: Response<'h>, state: &State) -> Response<'h, 3> { +async fn handler<'h>(req: Request<'h>, res: Response<'h>, state: &State) -> Response<'h, 3> { // unrealistic due to no http method check - match req.path.unwrap_or("404") { + match req.path { // unrealistic due to no dynamic path matching "/plaintext" => { // unrealistic due to no body streaming and no post processing. violating middleware feature of xitca-web @@ -111,13 +117,13 @@ async fn handler<'h>(req: Request<'h, '_>, res: Response<'h>, state: &State { - let num = path_param(p); + p if p.starts_with("/q") => { + let num = p["/queries?q=".len()..].parse_query(); let worlds = state.client.get_worlds(num).await.unwrap(); json_response(res, state, &worlds) } - p if p.starts_with("/updates") => { - let num = path_param(p); + p if p.starts_with("/u") => { + let num = p["/updates?q=".len()..].parse_query(); let worlds = state.client.update(num).await.unwrap(); json_response(res, state, &worlds) } @@ -139,13 +145,3 @@ where buf.clear(); res } - -fn path_param(query: &str) -> u16 { - use atoi::FromRadix10; - let q = if let Some(pos) = query.find("?q") { - u16::from_radix_10(query.split_at(pos + 3).1.as_ref()).0 - } else { - 1 - }; - q.clamp(1, 500) -} diff --git a/frameworks/Rust/xitca-web/src/ser.rs b/frameworks/Rust/xitca-web/src/ser.rs index 3c630c54bc6..edf9183a8c0 100644 --- a/frameworks/Rust/xitca-web/src/ser.rs +++ b/frameworks/Rust/xitca-web/src/ser.rs @@ -8,7 +8,7 @@ use xitca_http::{ bytes::{BufMutWriter, Bytes}, http::{ self, - const_header_value::{JSON, TEXT, TEXT_HTML_UTF8}, + const_header_value::{JSON, TEXT_HTML_UTF8, TEXT_UTF8}, header::CONTENT_TYPE, IntoResponse as _, RequestExt, StatusCode, }, @@ -213,7 +213,7 @@ impl IntoResponse for Request { fn text_response(self) -> Result { let mut res = self.into_response(const { Bytes::from_static(HELLO_BYTES) }); - res.headers_mut().insert(CONTENT_TYPE, TEXT); + res.headers_mut().insert(CONTENT_TYPE, TEXT_UTF8); Ok(res) } diff --git a/frameworks/Rust/xitca-web/src/util.rs b/frameworks/Rust/xitca-web/src/util.rs index 9183d067f5d..3998a2ef1ec 100755 --- a/frameworks/Rust/xitca-web/src/util.rs +++ b/frameworks/Rust/xitca-web/src/util.rs @@ -10,34 +10,16 @@ pub trait QueryParse { impl QueryParse for Option<&str> { fn parse_query(self) -> u16 { - self.and_then(|this| { - use atoi::FromRadix10; - this.find('q') - .map(|pos| u16::from_radix_10(this.split_at(pos + 2).1.as_ref()).0) - }) - .unwrap_or(1) - .clamp(1, 500) + self.and_then(|q| q.find('q').map(|pos| q.split_at(pos + 2).1.parse_query())) + .unwrap_or(1) } } -pub fn bulk_update_gen(func: F) -> String -where - F: FnOnce(&mut String), -{ - const PREFIX: &str = "UPDATE world SET randomNumber = w.r FROM (VALUES "; - const SUFFIX: &str = ") AS w (i,r) WHERE world.id = w.i"; - - let mut query = String::from(PREFIX); - - func(&mut query); - - if query.ends_with(',') { - query.pop(); +impl QueryParse for &str { + fn parse_query(self) -> u16 { + use atoi::FromRadix10; + u16::from_radix_10(self.as_bytes()).0.clamp(1, 500) } - - query.push_str(SUFFIX); - - query } #[allow(clippy::declare_interior_mutable_const)] @@ -64,7 +46,7 @@ impl State { } #[cfg(not(target_arch = "wasm32"))] -mod non_wasm { +pub mod non_wasm { use rand::{rngs::SmallRng, Rng, SeedableRng}; pub struct Rand(SmallRng); diff --git a/frameworks/Rust/xitca-web/xitca-web-iou.dockerfile b/frameworks/Rust/xitca-web/xitca-web-iou.dockerfile deleted file mode 100644 index 461d5740603..00000000000 --- a/frameworks/Rust/xitca-web/xitca-web-iou.dockerfile +++ /dev/null @@ -1,10 +0,0 @@ -FROM rust:1.81 - -ADD ./ /xitca-web -WORKDIR /xitca-web - -RUN cargo build --release --bin xitca-web-iou --features io-uring,perf,pg,template - -EXPOSE 8080 - -CMD ./target/release/xitca-web-iou diff --git a/frameworks/Rust/xitca-web/xitca-web-unrealistic.dockerfile b/frameworks/Rust/xitca-web/xitca-web-unrealistic.dockerfile new file mode 100644 index 00000000000..f202947acc0 --- /dev/null +++ b/frameworks/Rust/xitca-web/xitca-web-unrealistic.dockerfile @@ -0,0 +1,10 @@ +FROM rust:1.81 + +ADD ./ /xitca-web +WORKDIR /xitca-web + +RUN cargo build --release --bin xitca-web-unrealistic --features perf,pg,template + +EXPOSE 8080 + +CMD ./target/release/xitca-web-unrealistic From 072be3bbd91124878a78d1c40a8112e1e4e4e0c9 Mon Sep 17 00:00:00 2001 From: cclilshy Date: Tue, 15 Oct 2024 01:32:50 +0800 Subject: [PATCH 148/204] [Laravel/ripple] added the command for publishing configuration (#9324) * [Laravel/ripple] Update some configurations to be compatible with the v0.6 * [Laravel/ripple] added the command for publishing configuration --- frameworks/PHP/laravel/benchmark_config.json | 6 +++--- ...ipple.dockerfile => laravel-ripple.dockerfile} | 15 ++++++++------- 2 files changed, 11 insertions(+), 10 deletions(-) rename frameworks/PHP/laravel/{laravel-pripple.dockerfile => laravel-ripple.dockerfile} (80%) diff --git a/frameworks/PHP/laravel/benchmark_config.json b/frameworks/PHP/laravel/benchmark_config.json index f8421378e51..053534b12fa 100644 --- a/frameworks/PHP/laravel/benchmark_config.json +++ b/frameworks/PHP/laravel/benchmark_config.json @@ -139,7 +139,7 @@ "notes": "", "versus": "php" }, - "pripple": { + "ripple": { "json_url": "/json", "db_url": "/db", "query_url": "/queries/", @@ -154,11 +154,11 @@ "language": "PHP", "flavor": "PHP8.3", "orm": "Full", - "platform": "PRipple", + "platform": "Ripple", "webserver": "PServer", "os": "Linux", "database_os": "Linux", - "display_name": "laravel-pripple", + "display_name": "laravel-ripple", "notes": "", "versus": "php" } diff --git a/frameworks/PHP/laravel/laravel-pripple.dockerfile b/frameworks/PHP/laravel/laravel-ripple.dockerfile similarity index 80% rename from frameworks/PHP/laravel/laravel-pripple.dockerfile rename to frameworks/PHP/laravel/laravel-ripple.dockerfile index 869661a0432..4f1bb8bc3a9 100644 --- a/frameworks/PHP/laravel/laravel-pripple.dockerfile +++ b/frameworks/PHP/laravel/laravel-ripple.dockerfile @@ -33,16 +33,17 @@ RUN mkdir -p bootstrap/cache \ storage/framework/views \ storage/framework/cache -# Configure RUN echo "PRP_HTTP_LISTEN=http://0.0.0.0:8080" >> .env -RUN echo "PRP_HTTP_COUNT=64" >> .env +RUN echo "PRP_HTTP_WORKERS=64" >> .env +RUN echo "PRP_HTTP_RELOAD=0" >> .env +RUN echo "PRP_HTTP_SANDBOX=1" >> .env +# Configure RUN composer install --quiet +RUN composer require cloudtay/ripple-driver --quiet +RUN php artisan vendor:publish --tag=ripple-config RUN php artisan optimize -RUN composer require cclilshy/p-ripple-drive --quiet -RUN composer update --quiet - +# Start EXPOSE 8080 - -ENTRYPOINT ["php","artisan","p:server","start"] +ENTRYPOINT ["php","artisan","ripple:server","start"] From 808b21e6886274b69bd90e83391a6fc93ecbee0a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Deleuze?= Date: Mon, 14 Oct 2024 19:33:08 +0200 Subject: [PATCH 149/204] [spring] Improve database tests (#9313) * [spring-webflux] Improve database tests - Improve the test reliability with a better random number generation mechanism - Improve the scalability of fortune test * [spring] Fix postgres deadlock The now fixed deadlock issue was only visible under high concurrency and was generating errors and leading to lower than expected performance. Sorting the worlds before updating them allows to avoid this issue. --- .../src/main/java/benchmark/Utils.java | 19 ++++++++++++ .../repository/R2dbcDbRepository.java | 31 ++++++++++++++----- .../main/java/benchmark/web/DbHandler.java | 15 ++++----- .../src/main/java/hello/web/DbHandler.java | 2 ++ 4 files changed, 50 insertions(+), 17 deletions(-) create mode 100644 frameworks/Java/spring-webflux/src/main/java/benchmark/Utils.java diff --git a/frameworks/Java/spring-webflux/src/main/java/benchmark/Utils.java b/frameworks/Java/spring-webflux/src/main/java/benchmark/Utils.java new file mode 100644 index 00000000000..4631be27f11 --- /dev/null +++ b/frameworks/Java/spring-webflux/src/main/java/benchmark/Utils.java @@ -0,0 +1,19 @@ +package benchmark; + +import java.util.concurrent.ThreadLocalRandom; +import java.util.stream.IntStream; + +abstract public class Utils { + + private static final int MIN_WORLD_NUMBER = 1; + private static final int MAX_WORLD_NUMBER_PLUS_ONE = 10_001; + + public static int randomWorldNumber() { + return ThreadLocalRandom.current().nextInt(MIN_WORLD_NUMBER, MAX_WORLD_NUMBER_PLUS_ONE); + } + + public static IntStream randomWorldNumbers() { + return ThreadLocalRandom.current().ints(MIN_WORLD_NUMBER, MAX_WORLD_NUMBER_PLUS_ONE).distinct(); + } + +} diff --git a/frameworks/Java/spring-webflux/src/main/java/benchmark/repository/R2dbcDbRepository.java b/frameworks/Java/spring-webflux/src/main/java/benchmark/repository/R2dbcDbRepository.java index c7cfb89dea4..3cbf5f66d4a 100644 --- a/frameworks/Java/spring-webflux/src/main/java/benchmark/repository/R2dbcDbRepository.java +++ b/frameworks/Java/spring-webflux/src/main/java/benchmark/repository/R2dbcDbRepository.java @@ -1,20 +1,27 @@ package benchmark.repository; -import benchmark.model.Fortune; -import benchmark.model.World; import org.springframework.context.annotation.Profile; import org.springframework.r2dbc.core.DatabaseClient; import org.springframework.stereotype.Component; + +import benchmark.model.Fortune; +import benchmark.model.World; +import io.r2dbc.spi.Connection; +import io.r2dbc.spi.ConnectionFactory; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; @Component @Profile("r2dbc") public class R2dbcDbRepository implements DbRepository { + private final DatabaseClient databaseClient; + private final ConnectionFactory connectionFactory; + private final ThreadLocal> conn = new ThreadLocal<>(); public R2dbcDbRepository(DatabaseClient databaseClient) { this.databaseClient = databaseClient; + this.connectionFactory = databaseClient.getConnectionFactory(); } @Override @@ -24,10 +31,9 @@ public Mono getWorld(int id) { .bind("$1", id) .mapProperties(World.class) .first(); - } - public Mono updateWorld(World world) { + private Mono updateWorld(World world) { return databaseClient .sql("UPDATE world SET randomnumber=$2 WHERE id = $1") .bind("$1", world.id) @@ -37,6 +43,8 @@ public Mono updateWorld(World world) { .map(count -> world); } + + @Override public Mono findAndUpdateWorld(int id, int randomNumber) { return getWorld(id).flatMap(world -> { world.randomnumber = randomNumber; @@ -46,9 +54,16 @@ public Mono findAndUpdateWorld(int id, int randomNumber) { @Override public Flux fortunes() { - return databaseClient - .sql("SELECT id, message FROM fortune") - .mapProperties(Fortune.class) - .all(); + return getConnection() + .flatMapMany(conn -> conn.createStatement("SELECT id, message FROM " + "fortune").execute()) + .flatMap(result -> result.map(r -> new Fortune(r.get(0, Integer.class), r.get(1, String.class)))); } + + private Mono getConnection() { + if (this.conn.get() == null) { + this.conn.set(Mono.from(connectionFactory.create()).cache()); + } + return this.conn.get(); + } + } \ No newline at end of file diff --git a/frameworks/Java/spring-webflux/src/main/java/benchmark/web/DbHandler.java b/frameworks/Java/spring-webflux/src/main/java/benchmark/web/DbHandler.java index 970ace1d46d..e85d9c5be15 100644 --- a/frameworks/Java/spring-webflux/src/main/java/benchmark/web/DbHandler.java +++ b/frameworks/Java/spring-webflux/src/main/java/benchmark/web/DbHandler.java @@ -1,8 +1,8 @@ package benchmark.web; import java.util.List; -import java.util.concurrent.ThreadLocalRandom; +import benchmark.Utils; import benchmark.model.Fortune; import benchmark.model.World; import benchmark.repository.DbRepository; @@ -29,7 +29,7 @@ public DbHandler(DbRepository dbRepository) { } public Mono db(ServerRequest request) { - int id = randomWorldNumber(); + int id = Utils.randomWorldNumber(); Mono world = dbRepository.getWorld(id) .switchIfEmpty(Mono.error(new Exception("No World found with Id: " + id))); @@ -41,8 +41,8 @@ public Mono db(ServerRequest request) { public Mono queries(ServerRequest request) { int queries = parseQueryCount(request.queryParams().getFirst("queries")); - Mono> worlds = Flux.range(0, queries) - .flatMap(i -> dbRepository.getWorld(randomWorldNumber())) + Mono> worlds = Flux.fromStream(Utils.randomWorldNumbers().limit(queries).boxed()) + .flatMap(dbRepository::getWorld) .collectList(); return ServerResponse.ok() @@ -67,8 +67,8 @@ private static int parseQueryCount(String maybeTextValue) { public Mono updates(ServerRequest request) { int queries = parseQueryCount(request.queryParams().getFirst("queries")); - Mono> worlds = Flux.range(0, queries) - .flatMap(i -> dbRepository.findAndUpdateWorld(randomWorldNumber(), randomWorldNumber())) + Mono> worlds = Flux.fromStream(Utils.randomWorldNumbers().limit(queries).boxed()) + .flatMap(i -> dbRepository.findAndUpdateWorld(i, Utils.randomWorldNumber())) .collectList(); return ServerResponse.ok() @@ -87,7 +87,4 @@ public Mono fortunes(ServerRequest request) { .bodyValue(JStachio.render(new Fortunes(fortunes)))); } - private static int randomWorldNumber() { - return 1 + ThreadLocalRandom.current().nextInt(10000); - } } \ No newline at end of file diff --git a/frameworks/Java/spring/src/main/java/hello/web/DbHandler.java b/frameworks/Java/spring/src/main/java/hello/web/DbHandler.java index affb752268f..983eb79f6b9 100644 --- a/frameworks/Java/spring/src/main/java/hello/web/DbHandler.java +++ b/frameworks/Java/spring/src/main/java/hello/web/DbHandler.java @@ -1,6 +1,7 @@ package hello.web; import java.util.Collections; +import java.util.Comparator; import java.util.List; import hello.Utils; @@ -52,6 +53,7 @@ ServerResponse updates(ServerRequest request) { world.randomNumber = randomNumber; return world; }).limit(queries) + .sorted(Comparator.comparingInt(w -> w.id)) .toList(); dbRepository.updateWorlds(worlds); return ServerResponse.ok() From 313487b5fe55d546e34f0b698ce94a1331f7cfaf Mon Sep 17 00:00:00 2001 From: Petrik de Heus Date: Mon, 14 Oct 2024 19:34:33 +0200 Subject: [PATCH 150/204] [rails] Use higher log level (#9319) Using a higher log level bypasses a lot of unused instrumentation code. +-------------------------+---------+------+------+-----+-----+-------+------------+--------------+ | branch_name|plaintext|update| json| db|query|fortune|cached-query|weighted_score| +-------------------------+---------+------+------+-----+-----+-------+------------+--------------+ | master| 22816| 8249| 82981|21715|12531| 11234| 13259| 1006| | rails/increase-log-level| 24719| 11040| 90706|25126|16022| 16666| 14304| 1309| --- frameworks/Ruby/rails/config/environments/production.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frameworks/Ruby/rails/config/environments/production.rb b/frameworks/Ruby/rails/config/environments/production.rb index 45b097c9f04..c6594e5d17d 100644 --- a/frameworks/Ruby/rails/config/environments/production.rb +++ b/frameworks/Ruby/rails/config/environments/production.rb @@ -47,7 +47,7 @@ # "info" includes generic and useful information about system operation, but avoids logging too much # information to avoid inadvertent exposure of personally identifiable information (PII). If you # want to log everything, set the level to "debug". - config.log_level = ENV.fetch("RAILS_LOG_LEVEL", "info") + config.log_level = :fatal # Use a different cache store in production. config.cache_store = :redis_cache_store, { From 51155f12b2d2a4e71330aa3d724655cba5bda637 Mon Sep 17 00:00:00 2001 From: Santiago Pericas-Geertsen Date: Mon, 14 Oct 2024 13:35:13 -0400 Subject: [PATCH 151/204] Updates benchmark to latest version of Helidon (#9326) * Centralizes JSON serialization. Minor optimizations to pgclient repository implementation. Signed-off-by: Santiago Pericas-Geertsen * Fixes problem in PgClientRepository.getFortunes(). Signed-off-by: Santiago Pericas-Geertsen * Sets a VT factory for Hikari CP. Signed-off-by: Santiago Pericas-Geertsen * Additional configuration for Hikari CP. Signed-off-by: Santiago Pericas-Geertsen * Sets Helidon version to 4.1.2. Signed-off-by: Santiago Pericas-Geertsen * Set content type in response. Fixes problems with JSON serialization. Signed-off-by: Santiago Pericas-Geertsen --------- Signed-off-by: Santiago Pericas-Geertsen --- frameworks/Java/helidon/nima/pom.xml | 2 +- .../benchmark/nima/JsonSerializer.java | 92 +++++++++++++++ .../java/io/helidon/benchmark/nima/Main.java | 58 +--------- .../benchmark/nima/models/DbRepository.java | 19 ---- .../nima/models/HikariJdbcRepository.java | 21 +++- .../nima/models/PgClientRepository.java | 105 ++++++++---------- .../helidon/benchmark/nima/models/World.java | 6 +- .../benchmark/nima/services/DbService.java | 31 ++---- .../nima/src/main/resources/application.yaml | 1 + 9 files changed, 177 insertions(+), 158 deletions(-) create mode 100644 frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/JsonSerializer.java diff --git a/frameworks/Java/helidon/nima/pom.xml b/frameworks/Java/helidon/nima/pom.xml index c884659a0a0..c859b758cfc 100644 --- a/frameworks/Java/helidon/nima/pom.xml +++ b/frameworks/Java/helidon/nima/pom.xml @@ -21,7 +21,7 @@ io.helidon.applications helidon-se - 4.0.3 + 4.1.2 diff --git a/frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/JsonSerializer.java b/frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/JsonSerializer.java new file mode 100644 index 00000000000..322a7cf030c --- /dev/null +++ b/frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/JsonSerializer.java @@ -0,0 +1,92 @@ +package io.helidon.benchmark.nima; + +import java.io.IOException; +import java.util.Arrays; +import java.util.Map; +import java.util.List; + +import com.jsoniter.output.JsonStream; +import com.jsoniter.output.JsonStreamPool; +import com.jsoniter.spi.JsonException; + +public class JsonSerializer { + + private JsonSerializer() { + } + + /** + * Serialize an instance into a JSON object and return it as a byte array. + * + * @param obj the instance + * @return the byte array + */ + public static byte[] serialize(Object obj) { + JsonStream stream = JsonStreamPool.borrowJsonStream(); + try { + stream.reset(null); + stream.writeVal(obj.getClass(), obj); + return Arrays.copyOfRange(stream.buffer().data(), 0, stream.buffer().tail()); + } catch (IOException e) { + throw new JsonException(e); + } finally { + JsonStreamPool.returnJsonStream(stream); + } + } + + /** + * Serialize a map of strings into a JSON object and return it as a byte array. + * + * @param map the map + * @return the byte array + */ + public static byte[] serialize(Map map) { + JsonStream stream = JsonStreamPool.borrowJsonStream(); + try { + stream.reset(null); + stream.writeObjectStart(); + map.forEach((k, v) -> { + try { + stream.writeObjectField(k); + stream.writeVal(v); + } catch (Exception e) { + throw new RuntimeException(e); + } + }); + stream.writeObjectEnd(); + return Arrays.copyOfRange(stream.buffer().data(), 0, stream.buffer().tail()); + } catch (IOException e) { + throw new JsonException(e); + } finally { + JsonStreamPool.returnJsonStream(stream); + } + } + + /** + * Serialize a list of objects into a JSON array and return it as a byte array. + * + * @param objs the list of objects + * @return the byte array + */ + public static byte[] serialize(List objs) { + JsonStream stream = JsonStreamPool.borrowJsonStream(); + try { + stream.reset(null); + stream.writeArrayStart(); + int i = 0; + int n = objs.size(); + for (Object obj : objs) { + stream.writeVal(obj.getClass(), obj); + if (i++ < n - 1) { + stream.writeMore(); + } + + } + stream.writeArrayEnd(); + return Arrays.copyOfRange(stream.buffer().data(), 0, stream.buffer().tail()); + } catch (IOException e) { + throw new JsonException(e); + } finally { + JsonStreamPool.returnJsonStream(stream); + } + } +} diff --git a/frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/Main.java b/frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/Main.java index 92896867246..df669d8a7a7 100644 --- a/frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/Main.java +++ b/frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/Main.java @@ -16,14 +16,9 @@ package io.helidon.benchmark.nima; -import java.io.IOException; import java.nio.charset.StandardCharsets; -import java.util.Arrays; import java.util.logging.Logger; -import com.jsoniter.output.JsonStream; -import com.jsoniter.output.JsonStreamPool; -import com.jsoniter.spi.JsonException; import io.helidon.benchmark.nima.models.DbRepository; import io.helidon.benchmark.nima.models.HikariJdbcRepository; import io.helidon.benchmark.nima.models.PgClientRepository; @@ -41,6 +36,8 @@ import io.helidon.webserver.http.ServerRequest; import io.helidon.webserver.http.ServerResponse; +import static io.helidon.benchmark.nima.JsonSerializer.serialize; + /** * Main class of the benchmark. * Opens server on localhost:8080 and exposes {@code /plaintext} and {@code /json} endpoints adhering to the @@ -90,29 +87,14 @@ static void routing(HttpRules rules) { rules.get("/plaintext", new PlaintextHandler()) .get("/json", new JsonHandler()) - .get("/10k", new JsonKHandler(10)) .get("/fortunes", new FortuneHandler(repository)) .register("/", new DbService(repository)); } - private static byte[] serializeMsg(Message obj) { - JsonStream stream = JsonStreamPool.borrowJsonStream(); - try { - stream.reset(null); - stream.writeVal(Message.class, obj); - return Arrays.copyOfRange(stream.buffer().data(), 0, stream.buffer().tail()); - } catch (IOException e) { - throw new JsonException(e); - } finally { - JsonStreamPool.returnJsonStream(stream); - } - } - static class PlaintextHandler implements Handler { static final Header CONTENT_TYPE = HeaderValues.createCached(HeaderNames.CONTENT_TYPE, - "text/plain; charset=UTF-8"); + "text/plain; charset=UTF-8"); static final Header CONTENT_LENGTH = HeaderValues.createCached(HeaderNames.CONTENT_LENGTH, "13"); - private static final byte[] RESPONSE_BYTES = "Hello, World!".getBytes(StandardCharsets.UTF_8); @Override @@ -126,44 +108,16 @@ public void handle(ServerRequest req, ServerResponse res) { static class JsonHandler implements Handler { private static final String MESSAGE = "Hello, World!"; - private static final int JSON_LENGTH = serializeMsg(new Message(MESSAGE)).length; + private static final int JSON_LENGTH = serialize(new Message(MESSAGE)).length; static final Header CONTENT_LENGTH = HeaderValues.createCached(HeaderNames.CONTENT_LENGTH, - String.valueOf(JSON_LENGTH)); + String.valueOf(JSON_LENGTH)); @Override public void handle(ServerRequest req, ServerResponse res) { res.header(CONTENT_LENGTH); res.header(HeaderValues.CONTENT_TYPE_JSON); res.header(Main.SERVER); - res.send(serializeMsg(newMsg())); - } - - private static Message newMsg() { - return new Message("Hello, World!"); - } - } - - static class JsonKHandler implements Handler { - private final Header contentLength; - private final String message; - - JsonKHandler(int kilobytes) { - this.message = "a".repeat(1024 * kilobytes); - int length = serializeMsg(new Message(message)).length; - this.contentLength = HeaderValues.createCached(HeaderNames.CONTENT_LENGTH, - String.valueOf(length)); - } - - @Override - public void handle(ServerRequest req, ServerResponse res) { - res.header(contentLength); - res.header(HeaderValues.CONTENT_TYPE_JSON); - res.header(Main.SERVER); - res.send(serializeMsg(newMsg())); - } - - private Message newMsg() { - return new Message(message); + res.send(serialize(new Message(MESSAGE))); } } diff --git a/frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/models/DbRepository.java b/frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/models/DbRepository.java index 204c9ad5ad1..d1f75b558c3 100644 --- a/frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/models/DbRepository.java +++ b/frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/models/DbRepository.java @@ -6,35 +6,16 @@ import java.util.concurrent.ThreadLocalRandom; import jakarta.json.Json; -import jakarta.json.JsonArray; -import jakarta.json.JsonArrayBuilder; import jakarta.json.JsonBuilderFactory; -import jakarta.json.JsonObject; public interface DbRepository { JsonBuilderFactory JSON = Json.createBuilderFactory(Collections.emptyMap()); - default World getWorld() { - return getWorld(randomWorldNumber()); - } - World getWorld(int id); - default JsonObject getWorldAsJson(int id) { - return getWorld().toJson(); - } - List getWorlds(int count); - default JsonArray getWorldsAsJson(int count) { - JsonArrayBuilder result = JSON.createArrayBuilder(); - for (World world : getWorlds(count)) { - result.add(world.toJson()); - } - return result.build(); - } - World updateWorld(World world); List updateWorlds(int count); diff --git a/frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/models/HikariJdbcRepository.java b/frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/models/HikariJdbcRepository.java index 686559b2fd9..fd9760939df 100644 --- a/frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/models/HikariJdbcRepository.java +++ b/frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/models/HikariJdbcRepository.java @@ -7,6 +7,8 @@ import java.sql.SQLException; import java.util.ArrayList; import java.util.List; +import java.util.concurrent.Executors; +import java.util.concurrent.ThreadFactory; import java.util.logging.Logger; import com.zaxxer.hikari.HikariConfig; @@ -22,20 +24,31 @@ public class HikariJdbcRepository implements DbRepository { private final HikariConfig hikariConfig; public HikariJdbcRepository(Config config) { + // hikari connection configuration String url = "jdbc:postgresql://" + config.get("host").asString().orElse("tfb-database") + ":" + config.get("port").asString().orElse("5432") + "/" + config.get("db").asString().orElse("hello_world"); - hikariConfig = new HikariConfig(); hikariConfig.setJdbcUrl(url); hikariConfig.setUsername(config.get("username").asString().orElse("benchmarkdbuser")); hikariConfig.setPassword(config.get("password").asString().orElse("benchmarkdbpass")); - hikariConfig.addDataSourceProperty("cachePrepStmts", "true"); + // hikari additional configuration int poolSize = config.get("sql-pool-size").asInt().orElse(64); - hikariConfig.addDataSourceProperty("maximumPoolSize", poolSize); - LOGGER.info("Db pool size is set to " + poolSize); + hikariConfig.setMaximumPoolSize(poolSize); + LOGGER.info("Hikari pool size is set to " + poolSize); + ThreadFactory vtThreadFactory = Thread.ofVirtual().factory(); + hikariConfig.setThreadFactory(vtThreadFactory); + hikariConfig.setScheduledExecutor(Executors.newScheduledThreadPool(poolSize, vtThreadFactory)); + LOGGER.info("Set thread factory to VTs"); + + // data source properties + hikariConfig.addDataSourceProperty("cachePrepStmts","true"); + hikariConfig.addDataSourceProperty("prepStmtCacheSize","250"); + hikariConfig.addDataSourceProperty("prepStmtCacheSqlLimit","2048"); + hikariConfig.addDataSourceProperty("ssl", "false"); + hikariConfig.addDataSourceProperty("tcpKeepAlive", "true"); } private Connection getConnection() throws SQLException { diff --git a/frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/models/PgClientRepository.java b/frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/models/PgClientRepository.java index 7775a177537..e5166b10fbc 100644 --- a/frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/models/PgClientRepository.java +++ b/frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/models/PgClientRepository.java @@ -8,27 +8,25 @@ import java.util.concurrent.TimeoutException; import java.util.logging.Logger; -import io.helidon.common.reactive.Multi; -import io.helidon.common.reactive.Single; import io.helidon.config.Config; + import io.vertx.core.Vertx; import io.vertx.core.VertxOptions; +import io.vertx.core.Future; import io.vertx.pgclient.PgConnectOptions; import io.vertx.pgclient.PgPool; import io.vertx.sqlclient.PoolOptions; +import io.vertx.sqlclient.PreparedQuery; import io.vertx.sqlclient.Row; +import io.vertx.sqlclient.RowSet; import io.vertx.sqlclient.SqlClient; import io.vertx.sqlclient.Tuple; -import jakarta.json.JsonArray; -import jakarta.json.JsonArrayBuilder; -import jakarta.json.JsonObject; import static io.helidon.benchmark.nima.models.DbRepository.randomWorldNumber; public class PgClientRepository implements DbRepository { private static final Logger LOGGER = Logger.getLogger(PgClientRepository.class.getName()); - private final SqlClient queryPool; private final SqlClient updatePool; @@ -36,9 +34,13 @@ public class PgClientRepository implements DbRepository { private final long updateTimeout; private final int maxRetries; + private final PreparedQuery> getFortuneQuery; + private final PreparedQuery> getWorldQuery; + private final PreparedQuery> updateWorldQuery; + public PgClientRepository(Config config) { Vertx vertx = Vertx.vertx(new VertxOptions() - .setPreferNativeTransport(true)); + .setPreferNativeTransport(true)); PgConnectOptions connectOptions = new PgConnectOptions() .setPort(config.get("port").asInt().orElse(5432)) .setCachePreparedStatements(config.get("cache-prepared-statements").asBoolean().orElse(true)) @@ -59,31 +61,20 @@ public PgClientRepository(Config config) { queryPool = PgPool.client(vertx, connectOptions, clientOptions); updatePool = PgPool.client(vertx, connectOptions, clientOptions); - } - @Override - public JsonObject getWorldAsJson(int id) { - return getWorld(id, queryPool).map(World::toJson).await(); + getWorldQuery = queryPool.preparedQuery("SELECT id, randomnumber FROM world WHERE id = $1"); + updateWorldQuery = queryPool.preparedQuery("UPDATE world SET randomnumber = $1 WHERE id = $2"); + getFortuneQuery = queryPool.preparedQuery("SELECT id, message FROM fortune"); } @Override public World getWorld(int id) { try { - return getWorld(id, queryPool).toCompletableFuture().get(); - } catch (Exception e) { - throw new RuntimeException(e); - } - } - - @Override - public JsonArray getWorldsAsJson(int count) { - try { - return Multi.range(0, count) - .flatMap(i -> getWorld(randomWorldNumber(), queryPool)) - .map(World::toJson) - .reduce(JSON::createArrayBuilder, JsonArrayBuilder::add) - .map(JsonArrayBuilder::build) - .await(); + return getWorldQuery.execute(Tuple.of(id)) + .map(rows -> { + Row r = rows.iterator().next(); + return new World(r.getInteger(0), r.getInteger(1)); + }).toCompletionStage().toCompletableFuture().get(); } catch (Exception e) { throw new RuntimeException(e); } @@ -92,17 +83,15 @@ public JsonArray getWorldsAsJson(int count) { @Override public List getWorlds(int count) { try { - List result = new ArrayList<>(count); + List> futures = new ArrayList<>(); for (int i = 0; i < count; i++) { - World world = queryPool.preparedQuery("SELECT id, randomnumber FROM world WHERE id = $1") - .execute(Tuple.of(randomWorldNumber())) - .map(rows -> { - Row r = rows.iterator().next(); - return new World(r.getInteger(0), r.getInteger(1)); - }).toCompletionStage().toCompletableFuture().get(); - result.add(world); + futures.add(getWorldQuery.execute(Tuple.of(randomWorldNumber())) + .map(rows -> { + Row r = rows.iterator().next(); + return new World(r.getInteger(0), r.getInteger(1)); + })); } - return result; + return Future.all(futures).toCompletionStage().toCompletableFuture().get().list(); } catch (Exception e) { throw new RuntimeException(e); } @@ -110,10 +99,14 @@ public List getWorlds(int count) { @Override public World updateWorld(World world) { - return Single.create(queryPool.preparedQuery("UPDATE world SET randomnumber = $1 WHERE id = $2") - .execute(Tuple.of(world.id, world.id)) - .toCompletionStage() - .thenApply(rows -> world)).await(); + try { + return updateWorldQuery.execute(Tuple.of(world.id, world.id)) + .toCompletionStage() + .thenApply(rows -> world) + .toCompletableFuture().get(); + } catch (Exception e) { + throw new RuntimeException(e); + } } @Override @@ -165,25 +158,18 @@ private List updateWorldsRetry(List worlds, int from, int retries) @Override public List getFortunes() { - return Single.create(queryPool.preparedQuery("SELECT id, message FROM fortune") - .execute() - .map(rows -> { - List fortunes = new ArrayList<>(rows.size() + 1); - for (Row r : rows) { - fortunes.add(new Fortune(r.getInteger(0), r.getString(1))); - } - return fortunes; - }).toCompletionStage()).await(); - } - - private static Single getWorld(int id, SqlClient pool) { - return Single.create(pool.preparedQuery("SELECT id, randomnumber FROM world WHERE id = $1") - .execute(Tuple.of(id)) - .map(rows -> { - Row r = rows.iterator().next(); - return new World(r.getInteger(0), r.getInteger(1)); - }).toCompletionStage()); - + try { + return getFortuneQuery.execute() + .map(rows -> { + List fortunes = new ArrayList<>(rows.size() + 1); + for (Row r : rows) { + fortunes.add(new Fortune(r.getInteger(0), r.getString(1))); + } + return fortunes; + }).toCompletionStage().toCompletableFuture().get(); + } catch (Exception e) { + throw new RuntimeException(e); + } } private CompletableFuture> updateWorlds(List worlds, int from, SqlClient pool) { @@ -193,8 +179,7 @@ private CompletableFuture> updateWorlds(List worlds, int from World w = worlds.get(i); tuples.add(Tuple.of(w.randomNumber, w.id)); } - return pool.preparedQuery("UPDATE world SET randomnumber = $1 WHERE id = $2") - .executeBatch(tuples) + return updateWorldQuery.executeBatch(tuples) .toCompletionStage() .thenApply(rows -> worlds) .toCompletableFuture(); diff --git a/frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/models/World.java b/frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/models/World.java index ee8eb9194cd..39deafea11b 100644 --- a/frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/models/World.java +++ b/frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/models/World.java @@ -9,9 +9,9 @@ public final class World { - private static final String ID_KEY = "id"; - private static final String ID_RANDOM_NUMBER = "randomNumber"; - private static final JsonBuilderFactory JSON = Json.createBuilderFactory(Collections.emptyMap()); + static final String ID_KEY = "id"; + static final String ID_RANDOM_NUMBER = "randomNumber"; + static final JsonBuilderFactory JSON = Json.createBuilderFactory(Collections.emptyMap()); public int id; public int randomNumber; diff --git a/frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/services/DbService.java b/frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/services/DbService.java index 46c244d96f5..e3bd1fe39fc 100644 --- a/frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/services/DbService.java +++ b/frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/services/DbService.java @@ -1,27 +1,23 @@ package io.helidon.benchmark.nima.services; -import java.util.Collections; import java.util.List; import io.helidon.benchmark.nima.models.DbRepository; import io.helidon.benchmark.nima.models.World; import io.helidon.common.parameters.Parameters; +import io.helidon.http.HeaderValues; import io.helidon.webserver.http.HttpRules; import io.helidon.webserver.http.HttpService; import io.helidon.webserver.http.ServerRequest; import io.helidon.webserver.http.ServerResponse; - -import jakarta.json.Json; -import jakarta.json.JsonArrayBuilder; -import jakarta.json.JsonBuilderFactory; -import jakarta.json.JsonObject; +import io.helidon.common.mapper.OptionalValue; import static io.helidon.benchmark.nima.Main.SERVER; import static io.helidon.benchmark.nima.models.DbRepository.randomWorldNumber; +import static io.helidon.benchmark.nima.JsonSerializer.serialize; public class DbService implements HttpService { - private static final JsonBuilderFactory JSON = Json.createBuilderFactory(Collections.emptyMap()); private final DbRepository repository; @@ -38,36 +34,33 @@ public void routing(HttpRules httpRules) { private void db(ServerRequest req, ServerResponse res) { res.header(SERVER); - res.send(repository.getWorldAsJson(randomWorldNumber())); + res.header(HeaderValues.CONTENT_TYPE_JSON); + res.send(serialize(repository.getWorld(randomWorldNumber()))); } private void queries(ServerRequest req, ServerResponse res) { res.header(SERVER); + res.header(HeaderValues.CONTENT_TYPE_JSON); int count = parseQueryCount(req.query()); - res.send(repository.getWorldsAsJson(count)); + res.send(serialize(repository.getWorlds(count))); } private void updates(ServerRequest req, ServerResponse res) { res.header(SERVER); + res.header(HeaderValues.CONTENT_TYPE_JSON); int count = parseQueryCount(req.query()); List worlds = repository.updateWorlds(count); - JsonArrayBuilder arrayBuilder = JSON.createArrayBuilder(); - for (World world : worlds) { - JsonObject json = world.toJson(); - arrayBuilder.add(json); - } - res.send(arrayBuilder.build()); + res.send(serialize(worlds)); } private int parseQueryCount(Parameters parameters) { - List values = parameters.all("queries"); - if (values.isEmpty()) { + OptionalValue value = parameters.first("queries"); + if (value.isEmpty()) { return 1; } - String first = values.get(0); int parsedValue; try { - parsedValue = Integer.parseInt(first, 10); + parsedValue = Integer.parseInt(value.get(), 10); } catch (NumberFormatException e) { return 1; } diff --git a/frameworks/Java/helidon/nima/src/main/resources/application.yaml b/frameworks/Java/helidon/nima/src/main/resources/application.yaml index ff4aa100b67..41f4d64ec12 100644 --- a/frameworks/Java/helidon/nima/src/main/resources/application.yaml +++ b/frameworks/Java/helidon/nima/src/main/resources/application.yaml @@ -19,6 +19,7 @@ server: port: 8080 backlog: 8192 write-queue-length: 8192 + smart-async-writes: true connection-options: read-timeout: PT0S connect-timeout: PT0S From 9c41401165cb12ba7425e3fd9138332c3ddf3614 Mon Sep 17 00:00:00 2001 From: Eddy Oyieko <67474838+mobley-trent@users.noreply.github.com> Date: Mon, 14 Oct 2024 20:37:30 +0300 Subject: [PATCH 152/204] [scala/zio-http] updated to the latest RC version (#9325) * [zio-http] updated to the latest RC version * updated build.sbt, Main.scala --- frameworks/Scala/zio-http/build.sbt | 15 ++-- .../Scala/zio-http/project/build.properties | 2 +- frameworks/Scala/zio-http/project/plugins.sbt | 2 +- .../Scala/zio-http/src/main/scala/Main.scala | 85 ++++++++++--------- 4 files changed, 53 insertions(+), 51 deletions(-) diff --git a/frameworks/Scala/zio-http/build.sbt b/frameworks/Scala/zio-http/build.sbt index 987ee8cbbd2..a985d9b5dc9 100644 --- a/frameworks/Scala/zio-http/build.sbt +++ b/frameworks/Scala/zio-http/build.sbt @@ -1,13 +1,14 @@ name := "zio-http" version := "1.0.0" -scalaVersion := "2.13.6" +scalaVersion := "2.13.14" lazy val root = (project in file(".")) .settings( - libraryDependencies ++= - Seq( - "com.github.plokhotnyuk.jsoniter-scala" %% "jsoniter-scala-core" % "2.9.1", - "com.github.plokhotnyuk.jsoniter-scala" %% "jsoniter-scala-macros" % "2.9.1" % "compile-internal", - "io.d11" % "zhttp" % "1.0.0-RC5", - ), + libraryDependencies += "dev.zio" %% "zio-http" % "3.0.0-RC10", testFrameworks += new TestFramework("zio.test.sbt.ZTestFramework"), + assembly / assemblyMergeStrategy := { + case x if x.contains("io.netty.versions.properties") => MergeStrategy.discard + case x => + val oldStrategy = (assembly / assemblyMergeStrategy).value + oldStrategy(x) + } ) diff --git a/frameworks/Scala/zio-http/project/build.properties b/frameworks/Scala/zio-http/project/build.properties index 215ddd2b39d..ee06c398644 100644 --- a/frameworks/Scala/zio-http/project/build.properties +++ b/frameworks/Scala/zio-http/project/build.properties @@ -1 +1 @@ -sbt.version = 1.5.5 \ No newline at end of file +sbt.version = 1.10.0 \ No newline at end of file diff --git a/frameworks/Scala/zio-http/project/plugins.sbt b/frameworks/Scala/zio-http/project/plugins.sbt index 585d1930dc6..ec25e7aa776 100644 --- a/frameworks/Scala/zio-http/project/plugins.sbt +++ b/frameworks/Scala/zio-http/project/plugins.sbt @@ -1 +1 @@ -addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "1.0.0") +addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "2.1.0") diff --git a/frameworks/Scala/zio-http/src/main/scala/Main.scala b/frameworks/Scala/zio-http/src/main/scala/Main.scala index b72da4e089c..8af102fd7f6 100644 --- a/frameworks/Scala/zio-http/src/main/scala/Main.scala +++ b/frameworks/Scala/zio-http/src/main/scala/Main.scala @@ -1,42 +1,43 @@ -import zhttp.http._ -import zhttp.service.Server -import zio.{App, ExitCode, URIO} -import com.github.plokhotnyuk.jsoniter_scala.macros._ -import com.github.plokhotnyuk.jsoniter_scala.core._ -import zhttp.http.Response - -import java.time.format.DateTimeFormatter -import java.time.{Instant, ZoneOffset} - -case class Message(message: String) - -object Main extends App { - val message: String = "Hello, World!" - implicit val codec: JsonValueCodec[Message] = JsonCodecMaker.make - - val app: Http[Any, HttpError, Request, Response] = Http.collect[Request] { - case Method.GET -> Root / "plaintext" => - Response.http( - content = HttpContent.Complete(message), - headers = Header.contentTypeTextPlain :: headers(), - ) - case Method.GET -> Root / "json" => - Response.http( - content = HttpContent.Complete(writeToString(Message(message))), - headers = Header.contentTypeJson :: headers(), - ) - } - - override def run(args: List[String]): URIO[zio.ZEnv, ExitCode] = Server.start(8080, app).exitCode - - val formatter: DateTimeFormatter = DateTimeFormatter.RFC_1123_DATE_TIME.withZone(ZoneOffset.UTC) - val constantHeaders: List[Header] = Header("server", "zio-http") :: Nil - @volatile var lastHeaders: (Long, List[Header]) = (0, Nil) - - def headers(): List[Header] = { - val t = System.currentTimeMillis() - if (t - lastHeaders._1 >= 1000) - lastHeaders = (t, Header("date", formatter.format(Instant.ofEpochMilli(t))) :: constantHeaders) - lastHeaders._2 - } -} +import zio._ +import zio.http._ +import zio.http.netty.NettyConfig +import zio.http.netty.NettyConfig.LeakDetectionLevel +import java.lang.{Runtime => JRuntime} + +object Main extends ZIOAppDefault { + + private val plainTextMessage: String = "hello, world!" + private val jsonMessage: String = """{"message": "hello, world!"}""" + + private val STATIC_SERVER_NAME = "zio-http" + private val NUM_PROCESSORS = JRuntime.getRuntime.availableProcessors() + + val app: Routes[Any, Response] = Routes( + Method.GET / "/plaintext" -> + Handler.fromResponse( + Response + .text(plainTextMessage) + .addHeader(Header.Server(STATIC_SERVER_NAME)), + ), + Method.GET / "/json" -> + Handler.fromResponse( + Response + .json(jsonMessage) + .addHeader(Header.Server(STATIC_SERVER_NAME)), + ), + ) + + private val config = Server.Config.default + .port(8080) + .enableRequestStreaming + + private val nettyConfig = NettyConfig.default + .leakDetection(LeakDetectionLevel.DISABLED) + .maxThreads(NUM_PROCESSORS) + + private val configLayer = ZLayer.succeed(config) + private val nettyConfigLayer = ZLayer.succeed(nettyConfig) + + val run: UIO[ExitCode] = + Server.serve(app).provide(configLayer, nettyConfigLayer, Server.customized).exitCode +} \ No newline at end of file From cae4e4320a8f836e68e85a360cc6b15e99fc7776 Mon Sep 17 00:00:00 2001 From: Fangdun Tsai Date: Tue, 15 Oct 2024 01:37:58 +0800 Subject: [PATCH 153/204] [Rust/Viz] viz v0.9.0 (#9307) --- frameworks/Rust/viz/Cargo.toml | 17 +++++++++++------ frameworks/Rust/viz/src/db_sqlx.rs | 6 +++--- frameworks/Rust/viz/templates/fortune.stpl | 4 ++-- 3 files changed, 16 insertions(+), 11 deletions(-) diff --git a/frameworks/Rust/viz/Cargo.toml b/frameworks/Rust/viz/Cargo.toml index f28595febb5..b2e90cb4836 100644 --- a/frameworks/Rust/viz/Cargo.toml +++ b/frameworks/Rust/viz/Cargo.toml @@ -24,23 +24,28 @@ path = "src/main_diesel.rs" required-features = ["diesel", "diesel-async", "sailfish"] [dependencies] -viz = "0.8" -hyper = "1.0" +viz = "0.9" +hyper = "1.4" hyper-util = "0.1" atoi = "2.0" serde = { version = "1.0", features = ["derive"] } -nanorand = "0.7" rand = { version = "0.8", features = ["small_rng"] } thiserror = "1.0" futures-util = "0.3" +[target.'cfg(not(unix))'.dependencies] +nanorand = { version = "0.7" } + +[target.'cfg(unix)'.dependencies] +nanorand = { version = "0.7", features = ["getrandom"] } + tokio = { version = "1", features = ["full"] } tokio-postgres = { version = "0.7", optional = true } -sqlx = { version = "0.7", features = [ +sqlx = { version = "0.8", features = [ "postgres", "macros", "runtime-tokio", - "tls-native-tls" + "tls-native-tls", ], optional = true } diesel = { version = "2.2", default-features = false, features = [ "i-implement-a-third-party-backend-and-opt-into-breaking-changes", @@ -53,7 +58,7 @@ diesel-async = { git = "https://github.com/weiznich/diesel_async.git", rev = "74 yarte = { version = "0.15", features = ["bytes-buf", "json"], optional = true } markup = { version = "0.15", optional = true } v_htmlescape = { version = "0.15", optional = true } -sailfish = { version = "0.8", optional = true } +sailfish = { version = "0.9", optional = true } [profile.release] lto = true diff --git a/frameworks/Rust/viz/src/db_sqlx.rs b/frameworks/Rust/viz/src/db_sqlx.rs index af8322e9d1d..40c39290265 100644 --- a/frameworks/Rust/viz/src/db_sqlx.rs +++ b/frameworks/Rust/viz/src/db_sqlx.rs @@ -60,7 +60,7 @@ pub async fn get_world( id: i32, ) -> Result { let mut args = PgArguments::default(); - args.add(id); + let _ = args.add(id); let world = sqlx::query_as_with("SELECT id, randomnumber FROM World WHERE id = $1", args) @@ -86,8 +86,8 @@ pub async fn update_worlds( for w in &worlds { let mut args = PgArguments::default(); - args.add(w.randomnumber); - args.add(w.id); + let _ = args.add(w.randomnumber); + let _ = args.add(w.id); sqlx::query_with("UPDATE World SET randomNumber = $1 WHERE id = $2", args) .execute(&mut *conn) diff --git a/frameworks/Rust/viz/templates/fortune.stpl b/frameworks/Rust/viz/templates/fortune.stpl index eb1abe6a4fa..874b48cc6f5 100644 --- a/frameworks/Rust/viz/templates/fortune.stpl +++ b/frameworks/Rust/viz/templates/fortune.stpl @@ -4,7 +4,7 @@ - <% for item in items { %><% } %> + <% for item in self.items { %><% } %>
    idmessage
    <%= item.id %><%= &*item.message %>
    <%= item.id %><%= &*item.message %>
    - \ No newline at end of file + From 1b2161a78292158a81c7d63c7bb742e05e6b69f8 Mon Sep 17 00:00:00 2001 From: Yan Kun <1939810907@qq.com> Date: Tue, 15 Oct 2024 01:38:23 +0800 Subject: [PATCH 154/204] [Scala/otavia] Turn off nio optimization. (#9318) --- frameworks/Scala/otavia/otavia-overshoot.dockerfile | 2 ++ frameworks/Scala/otavia/otavia.dockerfile | 2 ++ 2 files changed, 4 insertions(+) diff --git a/frameworks/Scala/otavia/otavia-overshoot.dockerfile b/frameworks/Scala/otavia/otavia-overshoot.dockerfile index 10df5b40e71..78a03840454 100644 --- a/frameworks/Scala/otavia/otavia-overshoot.dockerfile +++ b/frameworks/Scala/otavia/otavia-overshoot.dockerfile @@ -9,6 +9,8 @@ EXPOSE 8080 CMD java -server \ -Dcc.otavia.actor.worker.size=64 \ + -Dcc.otavia.buffer.page.size=8 \ + -Dio.netty5.noKeySetOptimization=true \ -jar \ out/benchmark/assembly.dest/out.jar \ jdbc:postgresql://tfb-database:5432/hello_world \ diff --git a/frameworks/Scala/otavia/otavia.dockerfile b/frameworks/Scala/otavia/otavia.dockerfile index 81e16063b03..f1bbd33234c 100644 --- a/frameworks/Scala/otavia/otavia.dockerfile +++ b/frameworks/Scala/otavia/otavia.dockerfile @@ -9,6 +9,8 @@ EXPOSE 8080 CMD java -server \ -Dcc.otavia.actor.worker.size=56 \ + -Dcc.otavia.buffer.page.size=8 \ + -Dio.netty5.noKeySetOptimization=true \ -jar \ out/benchmark/assembly.dest/out.jar \ jdbc:postgresql://tfb-database:5432/hello_world \ From c94f7f95bd751f86a57dea8b63fb8f336bdbbde3 Mon Sep 17 00:00:00 2001 From: Artur Date: Mon, 14 Oct 2024 19:39:06 +0200 Subject: [PATCH 155/204] feat: log testing docker resource usage statistics [ci fw-only Fortran/fortran.io] (#9238) --- toolset/benchmark/benchmarker.py | 41 +++++++++++++++++++++++++------- toolset/utils/docker_helper.py | 12 +++------- toolset/utils/results.py | 29 ++++++++++++---------- 3 files changed, 53 insertions(+), 29 deletions(-) diff --git a/toolset/benchmark/benchmarker.py b/toolset/benchmark/benchmarker.py index 84e6be29912..8b5ce49d65b 100644 --- a/toolset/benchmark/benchmarker.py +++ b/toolset/benchmark/benchmarker.py @@ -1,3 +1,6 @@ +import threading + +from docker.models.containers import Container from toolset.utils.output_helper import log, FNULL from toolset.utils.docker_helper import DockerHelper from toolset.utils.time_logger import TimeLogger @@ -263,12 +266,6 @@ def benchmark_type(test_type): log("BENCHMARKING %s ... " % test_type.upper(), file=benchmark_log) test = framework_test.runTests[test_type] - raw_file = self.results.get_raw_file(framework_test.name, - test_type) - if not os.path.exists(raw_file): - # Open to create the empty file - with open(raw_file, 'w'): - pass if not test.failed: # Begin resource usage metrics collection @@ -281,8 +278,8 @@ def benchmark_type(test_type): framework_test.port, test.get_url())) - self.docker_helper.benchmark(script, script_variables, - raw_file) + benchmark_container = self.docker_helper.benchmark(script, script_variables) + self.__log_container_output(benchmark_container, framework_test, test_type) # End resource usage metrics collection self.__end_logging() @@ -323,3 +320,31 @@ def __end_logging(self): self.subprocess_handle.terminate() self.subprocess_handle.communicate() + def __log_container_output(self, container: Container, framework_test, test_type) -> None: + def save_docker_logs(stream): + raw_file_path = self.results.get_raw_file(framework_test.name, test_type) + with open(raw_file_path, 'w') as file: + for line in stream: + log(line.decode(), file=file) + + def save_docker_stats(stream): + docker_file_path = self.results.get_docker_stats_file(framework_test.name, test_type) + with open(docker_file_path, 'w') as file: + file.write('[\n') + is_first_line = True + for line in stream: + if is_first_line: + is_first_line = False + else: + file.write(',') + file.write(line.decode()) + file.write(']') + + threads = [ + threading.Thread(target=lambda: save_docker_logs(container.logs(stream=True))), + threading.Thread(target=lambda: save_docker_stats(container.stats(stream=True))) + ] + + [thread.start() for thread in threads] + [thread.join() for thread in threads] + diff --git a/toolset/utils/docker_helper.py b/toolset/utils/docker_helper.py index 1f3ea692ee1..e48a910e99d 100644 --- a/toolset/utils/docker_helper.py +++ b/toolset/utils/docker_helper.py @@ -420,16 +420,11 @@ def server_container_exists(self, container_id_or_name): except: return False - def benchmark(self, script, variables, raw_file): + def benchmark(self, script, variables): ''' Runs the given remote_script on the wrk container on the client machine. ''' - def watch_container(container): - with open(raw_file, 'w') as benchmark_file: - for line in container.logs(stream=True): - log(line.decode(), file=benchmark_file) - if self.benchmarker.config.network_mode is None: sysctl = {'net.core.somaxconn': 65535} else: @@ -438,8 +433,7 @@ def watch_container(container): ulimit = [{'name': 'nofile', 'hard': 65535, 'soft': 65535}] - watch_container( - self.client.containers.run( + return self.client.containers.run( "techempower/tfb.wrk", "/bin/bash /%s" % script, environment=variables, @@ -450,4 +444,4 @@ def watch_container(container): ulimits=ulimit, sysctls=sysctl, remove=True, - log_config={'type': None})) + log_config={'type': None}) diff --git a/toolset/utils/results.py b/toolset/utils/results.py index 7b745a90bc0..0df26636404 100644 --- a/toolset/utils/results.py +++ b/toolset/utils/results.py @@ -212,29 +212,34 @@ def load(self): except (ValueError, IOError): pass + def __make_dir_for_file(self, test_name: str, test_type: str, file_name: str): + path = os.path.join(self.directory, test_name, test_type, file_name) + try: + os.makedirs(os.path.dirname(path), exist_ok=True) + except OSError: + pass + return path + + def get_docker_stats_file(self, test_name, test_type): + ''' + Returns the stats file name for this test_name and + Example: fw_root/results/timestamp/test_type/test_name/stats.txt + ''' + return self.__make_dir_for_file(test_name, test_type, "docker_stats.json") + def get_raw_file(self, test_name, test_type): ''' Returns the output file for this test_name and test_type Example: fw_root/results/timestamp/test_type/test_name/raw.txt ''' - path = os.path.join(self.directory, test_name, test_type, "raw.txt") - try: - os.makedirs(os.path.dirname(path)) - except OSError: - pass - return path + return self.__make_dir_for_file(test_name, test_type, "raw.txt") def get_stats_file(self, test_name, test_type): ''' Returns the stats file name for this test_name and Example: fw_root/results/timestamp/test_type/test_name/stats.txt ''' - path = os.path.join(self.directory, test_name, test_type, "stats.txt") - try: - os.makedirs(os.path.dirname(path)) - except OSError: - pass - return path + return self.__make_dir_for_file(test_name, test_type, "stats.txt") def report_verify_results(self, framework_test, test_type, result): ''' From 45dadf82f72c3ca7d9018b3edc052de7739d6b11 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 14 Oct 2024 20:48:28 +0000 Subject: [PATCH 156/204] Bump Microsoft.Extensions.Caching.Memory Bumps [Microsoft.Extensions.Caching.Memory](https://github.com/dotnet/runtime) from 8.0.0 to 8.0.1. - [Release notes](https://github.com/dotnet/runtime/releases) - [Commits](https://github.com/dotnet/runtime/compare/v8.0.0...v8.0.1) --- updated-dependencies: - dependency-name: Microsoft.Extensions.Caching.Memory dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- .../CSharp/beetlex/PlatformBenchmarks/PlatformBenchmarks.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frameworks/CSharp/beetlex/PlatformBenchmarks/PlatformBenchmarks.csproj b/frameworks/CSharp/beetlex/PlatformBenchmarks/PlatformBenchmarks.csproj index d6a786daa3b..7518d6b0de0 100644 --- a/frameworks/CSharp/beetlex/PlatformBenchmarks/PlatformBenchmarks.csproj +++ b/frameworks/CSharp/beetlex/PlatformBenchmarks/PlatformBenchmarks.csproj @@ -9,7 +9,7 @@ - + From 427066cc89b6415e7549a52c13efd0cf27c8cb32 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 14 Oct 2024 21:09:16 +0000 Subject: [PATCH 157/204] Bump org.eclipse.jetty:jetty-server in /frameworks/Java/jetty Bumps org.eclipse.jetty:jetty-server from 10.0.14 to 10.0.24. --- updated-dependencies: - dependency-name: org.eclipse.jetty:jetty-server dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- frameworks/Java/jetty/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frameworks/Java/jetty/pom.xml b/frameworks/Java/jetty/pom.xml index db5ba4a6b7b..6156c5603f8 100644 --- a/frameworks/Java/jetty/pom.xml +++ b/frameworks/Java/jetty/pom.xml @@ -11,7 +11,7 @@ UTF-8 11 11 - 10.0.14 + 10.0.24 hello.handler.HelloWebServer From dc0bded626057d0241e0a0fbda44acabfc31ca9f Mon Sep 17 00:00:00 2001 From: Roman Samoilov <2270393+rsamoilov@users.noreply.github.com> Date: Tue, 15 Oct 2024 19:19:24 +0100 Subject: [PATCH 158/204] [ruby/rage] Code cleanup (#9305) * Remove `load_middlewares` call `Rage.load_middlewares` was deprecated in v1.5 * Bump to Rage >= 1.10 * Remove `as_json` overrides * Remove env variable `RAGE_PATCH_AR_POOL` is enabled by default since v1.10 * Let Rage connect to the DB --- frameworks/Ruby/rage/Gemfile | 2 +- frameworks/Ruby/rage/app/models/fortune.rb | 4 ---- frameworks/Ruby/rage/app/models/world.rb | 4 ---- frameworks/Ruby/rage/config.ru | 1 - .../Ruby/rage/config/initializers/activerecord.rb | 15 +++------------ frameworks/Ruby/rage/rage.dockerfile | 1 - 6 files changed, 4 insertions(+), 23 deletions(-) diff --git a/frameworks/Ruby/rage/Gemfile b/frameworks/Ruby/rage/Gemfile index 96d6e7042fc..89c3affcb58 100644 --- a/frameworks/Ruby/rage/Gemfile +++ b/frameworks/Ruby/rage/Gemfile @@ -1,6 +1,6 @@ source "https://rubygems.org" -gem "rage-rb", "~> 1.3" +gem "rage-rb", "~> 1.10" gem "pg", "~> 1.0" gem "activerecord", "~> 7.2.0", require: "active_record" diff --git a/frameworks/Ruby/rage/app/models/fortune.rb b/frameworks/Ruby/rage/app/models/fortune.rb index 6b7ad122f80..0080d6363c4 100644 --- a/frameworks/Ruby/rage/app/models/fortune.rb +++ b/frameworks/Ruby/rage/app/models/fortune.rb @@ -1,7 +1,3 @@ class Fortune < ApplicationRecord self.table_name = "Fortune" - - def as_json(*) - attributes - end end diff --git a/frameworks/Ruby/rage/app/models/world.rb b/frameworks/Ruby/rage/app/models/world.rb index 951aab55b64..836783137c6 100644 --- a/frameworks/Ruby/rage/app/models/world.rb +++ b/frameworks/Ruby/rage/app/models/world.rb @@ -1,9 +1,5 @@ class World < ApplicationRecord self.table_name = "World" - def as_json(*) - attributes - end - alias_attribute(:randomNumber, :randomnumber) end diff --git a/frameworks/Ruby/rage/config.ru b/frameworks/Ruby/rage/config.ru index 52de8a40479..049a1ad509d 100644 --- a/frameworks/Ruby/rage/config.ru +++ b/frameworks/Ruby/rage/config.ru @@ -1,4 +1,3 @@ require_relative "config/application" run Rage.application -Rage.load_middlewares(self) diff --git a/frameworks/Ruby/rage/config/initializers/activerecord.rb b/frameworks/Ruby/rage/config/initializers/activerecord.rb index c0e3eb08d44..34a3b019a66 100644 --- a/frameworks/Ruby/rage/config/initializers/activerecord.rb +++ b/frameworks/Ruby/rage/config/initializers/activerecord.rb @@ -2,16 +2,7 @@ require "etc" -connection = { - adapter: "postgresql", - host: "tfb-database", - username: "benchmarkdbuser", - password: "benchmarkdbpass", - database: "hello_world", - reaping_frequency: 0, - pool: (2 * Math.log(256 / Etc.nprocessors)).floor -} +pool_size = (2 * Math.log(256 / Etc.nprocessors)).floor +puts "ActiveRecord pool size: #{pool_size}" -puts "ActiveRecord connection options: #{connection.inspect}" - -ActiveRecord::Base.establish_connection(connection) +ENV["DATABASE_URL"]="postgres://benchmarkdbuser:benchmarkdbpass@tfb-database/hello_world?pool=#{pool_size}&reaping_frequency=0" diff --git a/frameworks/Ruby/rage/rage.dockerfile b/frameworks/Ruby/rage/rage.dockerfile index bbacb344f29..6c65b51fba4 100644 --- a/frameworks/Ruby/rage/rage.dockerfile +++ b/frameworks/Ruby/rage/rage.dockerfile @@ -8,7 +8,6 @@ RUN bundle install --jobs=8 COPY . /rage ENV RUBY_YJIT_ENABLE=1 -ENV RAGE_PATCH_AR_POOL=1 ENV BUNDLE_FORCE_RUBY_PLATFORM=true CMD bundle exec rage s -b 0.0.0.0 -p 8080 -e production From 15f905aae6573cce50a062e59c80f7042b98a9d3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 15 Oct 2024 18:59:58 +0000 Subject: [PATCH 159/204] Bump starlette from 0.36.2 to 0.40.0 in /frameworks/Python/starlette Bumps [starlette](https://github.com/encode/starlette) from 0.36.2 to 0.40.0. - [Release notes](https://github.com/encode/starlette/releases) - [Changelog](https://github.com/encode/starlette/blob/master/docs/release-notes.md) - [Commits](https://github.com/encode/starlette/compare/0.36.2...0.40.0) --- updated-dependencies: - dependency-name: starlette dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- frameworks/Python/starlette/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frameworks/Python/starlette/requirements.txt b/frameworks/Python/starlette/requirements.txt index ef5a1748ca4..47b27a87e9a 100644 --- a/frameworks/Python/starlette/requirements.txt +++ b/frameworks/Python/starlette/requirements.txt @@ -6,6 +6,6 @@ Jinja2==3.1.4 MarkupSafe==2.1.1 python-dotenv==0.20.0 PyYAML==6.0 -starlette==0.36.2 +starlette==0.40.0 uvicorn==0.20.0 uvloop==0.17.0 From a9b944e3e276ac1b4bfa08ffe70f600b6fe8d06c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 15 Oct 2024 23:42:12 +0000 Subject: [PATCH 160/204] Bump actiontext from 7.2.0 to 7.2.1.1 in /frameworks/Ruby/rails Bumps [actiontext](https://github.com/rails/rails) from 7.2.0 to 7.2.1.1. - [Release notes](https://github.com/rails/rails/releases) - [Changelog](https://github.com/rails/rails/blob/v7.2.1.1/actiontext/CHANGELOG.md) - [Commits](https://github.com/rails/rails/compare/v7.2.0...v7.2.1.1) --- updated-dependencies: - dependency-name: actiontext dependency-type: indirect ... Signed-off-by: dependabot[bot] --- frameworks/Ruby/rails/Gemfile.lock | 114 ++++++++++++++--------------- 1 file changed, 57 insertions(+), 57 deletions(-) diff --git a/frameworks/Ruby/rails/Gemfile.lock b/frameworks/Ruby/rails/Gemfile.lock index dfa97091616..d92307f837d 100644 --- a/frameworks/Ruby/rails/Gemfile.lock +++ b/frameworks/Ruby/rails/Gemfile.lock @@ -1,29 +1,29 @@ GEM remote: https://rubygems.org/ specs: - actioncable (7.2.0) - actionpack (= 7.2.0) - activesupport (= 7.2.0) + actioncable (7.2.1.1) + actionpack (= 7.2.1.1) + activesupport (= 7.2.1.1) nio4r (~> 2.0) websocket-driver (>= 0.6.1) zeitwerk (~> 2.6) - actionmailbox (7.2.0) - actionpack (= 7.2.0) - activejob (= 7.2.0) - activerecord (= 7.2.0) - activestorage (= 7.2.0) - activesupport (= 7.2.0) + actionmailbox (7.2.1.1) + actionpack (= 7.2.1.1) + activejob (= 7.2.1.1) + activerecord (= 7.2.1.1) + activestorage (= 7.2.1.1) + activesupport (= 7.2.1.1) mail (>= 2.8.0) - actionmailer (7.2.0) - actionpack (= 7.2.0) - actionview (= 7.2.0) - activejob (= 7.2.0) - activesupport (= 7.2.0) + actionmailer (7.2.1.1) + actionpack (= 7.2.1.1) + actionview (= 7.2.1.1) + activejob (= 7.2.1.1) + activesupport (= 7.2.1.1) mail (>= 2.8.0) rails-dom-testing (~> 2.2) - actionpack (7.2.0) - actionview (= 7.2.0) - activesupport (= 7.2.0) + actionpack (7.2.1.1) + actionview (= 7.2.1.1) + activesupport (= 7.2.1.1) nokogiri (>= 1.8.5) racc rack (>= 2.2.4, < 3.2) @@ -32,35 +32,35 @@ GEM rails-dom-testing (~> 2.2) rails-html-sanitizer (~> 1.6) useragent (~> 0.16) - actiontext (7.2.0) - actionpack (= 7.2.0) - activerecord (= 7.2.0) - activestorage (= 7.2.0) - activesupport (= 7.2.0) + actiontext (7.2.1.1) + actionpack (= 7.2.1.1) + activerecord (= 7.2.1.1) + activestorage (= 7.2.1.1) + activesupport (= 7.2.1.1) globalid (>= 0.6.0) nokogiri (>= 1.8.5) - actionview (7.2.0) - activesupport (= 7.2.0) + actionview (7.2.1.1) + activesupport (= 7.2.1.1) builder (~> 3.1) erubi (~> 1.11) rails-dom-testing (~> 2.2) rails-html-sanitizer (~> 1.6) - activejob (7.2.0) - activesupport (= 7.2.0) + activejob (7.2.1.1) + activesupport (= 7.2.1.1) globalid (>= 0.3.6) - activemodel (7.2.0) - activesupport (= 7.2.0) - activerecord (7.2.0) - activemodel (= 7.2.0) - activesupport (= 7.2.0) + activemodel (7.2.1.1) + activesupport (= 7.2.1.1) + activerecord (7.2.1.1) + activemodel (= 7.2.1.1) + activesupport (= 7.2.1.1) timeout (>= 0.4.0) - activestorage (7.2.0) - actionpack (= 7.2.0) - activejob (= 7.2.0) - activerecord (= 7.2.0) - activesupport (= 7.2.0) + activestorage (7.2.1.1) + actionpack (= 7.2.1.1) + activejob (= 7.2.1.1) + activerecord (= 7.2.1.1) + activesupport (= 7.2.1.1) marcel (~> 1.0) - activesupport (7.2.0) + activesupport (7.2.1.1) base64 bigdecimal concurrent-ruby (~> 1.0, >= 1.3.1) @@ -82,13 +82,13 @@ GEM erubi (1.13.0) globalid (1.2.1) activesupport (>= 6.1) - i18n (1.14.5) + i18n (1.14.6) concurrent-ruby (~> 1.0) io-console (0.7.2) irb (1.14.0) rdoc (>= 4.0.0) reline (>= 0.4.2) - logger (1.6.0) + logger (1.6.1) loofah (2.22.0) crass (~> 1.0.2) nokogiri (>= 1.12.0) @@ -100,7 +100,7 @@ GEM marcel (1.0.4) mini_mime (1.1.5) mini_portile2 (2.8.7) - minitest (5.24.1) + minitest (5.25.1) net-imap (0.4.14) date net-protocol @@ -128,7 +128,7 @@ GEM puma (6.4.2) nio4r (~> 2.0) racc (1.8.1) - rack (3.1.7) + rack (3.1.8) rack-session (2.0.0) rack (>= 3.0.0) rack-test (2.1.0) @@ -136,20 +136,20 @@ GEM rackup (2.1.0) rack (>= 3) webrick (~> 1.8) - rails (7.2.0) - actioncable (= 7.2.0) - actionmailbox (= 7.2.0) - actionmailer (= 7.2.0) - actionpack (= 7.2.0) - actiontext (= 7.2.0) - actionview (= 7.2.0) - activejob (= 7.2.0) - activemodel (= 7.2.0) - activerecord (= 7.2.0) - activestorage (= 7.2.0) - activesupport (= 7.2.0) + rails (7.2.1.1) + actioncable (= 7.2.1.1) + actionmailbox (= 7.2.1.1) + actionmailer (= 7.2.1.1) + actionpack (= 7.2.1.1) + actiontext (= 7.2.1.1) + actionview (= 7.2.1.1) + activejob (= 7.2.1.1) + activemodel (= 7.2.1.1) + activerecord (= 7.2.1.1) + activestorage (= 7.2.1.1) + activesupport (= 7.2.1.1) bundler (>= 1.15.0) - railties (= 7.2.0) + railties (= 7.2.1.1) rails-dom-testing (2.2.0) activesupport (>= 5.0.0) minitest @@ -157,9 +157,9 @@ GEM rails-html-sanitizer (1.6.0) loofah (~> 2.21) nokogiri (~> 1.14) - railties (7.2.0) - actionpack (= 7.2.0) - activesupport (= 7.2.0) + railties (7.2.1.1) + actionpack (= 7.2.1.1) + activesupport (= 7.2.1.1) irb (~> 1.13) rackup (>= 1.0.0) rake (>= 12.2) From 33881f8e29d9512b0cc4928efc9482f2c9ddd00a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 15 Oct 2024 23:42:13 +0000 Subject: [PATCH 161/204] Bump actionpack from 7.2.0 to 7.2.1.1 in /frameworks/Ruby/rails Bumps [actionpack](https://github.com/rails/rails) from 7.2.0 to 7.2.1.1. - [Release notes](https://github.com/rails/rails/releases) - [Changelog](https://github.com/rails/rails/blob/v7.2.1.1/actionpack/CHANGELOG.md) - [Commits](https://github.com/rails/rails/compare/v7.2.0...v7.2.1.1) --- updated-dependencies: - dependency-name: actionpack dependency-type: indirect ... Signed-off-by: dependabot[bot] --- frameworks/Ruby/rails/Gemfile.lock | 114 ++++++++++++++--------------- 1 file changed, 57 insertions(+), 57 deletions(-) diff --git a/frameworks/Ruby/rails/Gemfile.lock b/frameworks/Ruby/rails/Gemfile.lock index dfa97091616..d92307f837d 100644 --- a/frameworks/Ruby/rails/Gemfile.lock +++ b/frameworks/Ruby/rails/Gemfile.lock @@ -1,29 +1,29 @@ GEM remote: https://rubygems.org/ specs: - actioncable (7.2.0) - actionpack (= 7.2.0) - activesupport (= 7.2.0) + actioncable (7.2.1.1) + actionpack (= 7.2.1.1) + activesupport (= 7.2.1.1) nio4r (~> 2.0) websocket-driver (>= 0.6.1) zeitwerk (~> 2.6) - actionmailbox (7.2.0) - actionpack (= 7.2.0) - activejob (= 7.2.0) - activerecord (= 7.2.0) - activestorage (= 7.2.0) - activesupport (= 7.2.0) + actionmailbox (7.2.1.1) + actionpack (= 7.2.1.1) + activejob (= 7.2.1.1) + activerecord (= 7.2.1.1) + activestorage (= 7.2.1.1) + activesupport (= 7.2.1.1) mail (>= 2.8.0) - actionmailer (7.2.0) - actionpack (= 7.2.0) - actionview (= 7.2.0) - activejob (= 7.2.0) - activesupport (= 7.2.0) + actionmailer (7.2.1.1) + actionpack (= 7.2.1.1) + actionview (= 7.2.1.1) + activejob (= 7.2.1.1) + activesupport (= 7.2.1.1) mail (>= 2.8.0) rails-dom-testing (~> 2.2) - actionpack (7.2.0) - actionview (= 7.2.0) - activesupport (= 7.2.0) + actionpack (7.2.1.1) + actionview (= 7.2.1.1) + activesupport (= 7.2.1.1) nokogiri (>= 1.8.5) racc rack (>= 2.2.4, < 3.2) @@ -32,35 +32,35 @@ GEM rails-dom-testing (~> 2.2) rails-html-sanitizer (~> 1.6) useragent (~> 0.16) - actiontext (7.2.0) - actionpack (= 7.2.0) - activerecord (= 7.2.0) - activestorage (= 7.2.0) - activesupport (= 7.2.0) + actiontext (7.2.1.1) + actionpack (= 7.2.1.1) + activerecord (= 7.2.1.1) + activestorage (= 7.2.1.1) + activesupport (= 7.2.1.1) globalid (>= 0.6.0) nokogiri (>= 1.8.5) - actionview (7.2.0) - activesupport (= 7.2.0) + actionview (7.2.1.1) + activesupport (= 7.2.1.1) builder (~> 3.1) erubi (~> 1.11) rails-dom-testing (~> 2.2) rails-html-sanitizer (~> 1.6) - activejob (7.2.0) - activesupport (= 7.2.0) + activejob (7.2.1.1) + activesupport (= 7.2.1.1) globalid (>= 0.3.6) - activemodel (7.2.0) - activesupport (= 7.2.0) - activerecord (7.2.0) - activemodel (= 7.2.0) - activesupport (= 7.2.0) + activemodel (7.2.1.1) + activesupport (= 7.2.1.1) + activerecord (7.2.1.1) + activemodel (= 7.2.1.1) + activesupport (= 7.2.1.1) timeout (>= 0.4.0) - activestorage (7.2.0) - actionpack (= 7.2.0) - activejob (= 7.2.0) - activerecord (= 7.2.0) - activesupport (= 7.2.0) + activestorage (7.2.1.1) + actionpack (= 7.2.1.1) + activejob (= 7.2.1.1) + activerecord (= 7.2.1.1) + activesupport (= 7.2.1.1) marcel (~> 1.0) - activesupport (7.2.0) + activesupport (7.2.1.1) base64 bigdecimal concurrent-ruby (~> 1.0, >= 1.3.1) @@ -82,13 +82,13 @@ GEM erubi (1.13.0) globalid (1.2.1) activesupport (>= 6.1) - i18n (1.14.5) + i18n (1.14.6) concurrent-ruby (~> 1.0) io-console (0.7.2) irb (1.14.0) rdoc (>= 4.0.0) reline (>= 0.4.2) - logger (1.6.0) + logger (1.6.1) loofah (2.22.0) crass (~> 1.0.2) nokogiri (>= 1.12.0) @@ -100,7 +100,7 @@ GEM marcel (1.0.4) mini_mime (1.1.5) mini_portile2 (2.8.7) - minitest (5.24.1) + minitest (5.25.1) net-imap (0.4.14) date net-protocol @@ -128,7 +128,7 @@ GEM puma (6.4.2) nio4r (~> 2.0) racc (1.8.1) - rack (3.1.7) + rack (3.1.8) rack-session (2.0.0) rack (>= 3.0.0) rack-test (2.1.0) @@ -136,20 +136,20 @@ GEM rackup (2.1.0) rack (>= 3) webrick (~> 1.8) - rails (7.2.0) - actioncable (= 7.2.0) - actionmailbox (= 7.2.0) - actionmailer (= 7.2.0) - actionpack (= 7.2.0) - actiontext (= 7.2.0) - actionview (= 7.2.0) - activejob (= 7.2.0) - activemodel (= 7.2.0) - activerecord (= 7.2.0) - activestorage (= 7.2.0) - activesupport (= 7.2.0) + rails (7.2.1.1) + actioncable (= 7.2.1.1) + actionmailbox (= 7.2.1.1) + actionmailer (= 7.2.1.1) + actionpack (= 7.2.1.1) + actiontext (= 7.2.1.1) + actionview (= 7.2.1.1) + activejob (= 7.2.1.1) + activemodel (= 7.2.1.1) + activerecord (= 7.2.1.1) + activestorage (= 7.2.1.1) + activesupport (= 7.2.1.1) bundler (>= 1.15.0) - railties (= 7.2.0) + railties (= 7.2.1.1) rails-dom-testing (2.2.0) activesupport (>= 5.0.0) minitest @@ -157,9 +157,9 @@ GEM rails-html-sanitizer (1.6.0) loofah (~> 2.21) nokogiri (~> 1.14) - railties (7.2.0) - actionpack (= 7.2.0) - activesupport (= 7.2.0) + railties (7.2.1.1) + actionpack (= 7.2.1.1) + activesupport (= 7.2.1.1) irb (~> 1.13) rackup (>= 1.0.0) rake (>= 12.2) From ee7f895d6b213deee2a8cf846dbeeb5d972e38af Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 16 Oct 2024 14:13:40 +0000 Subject: [PATCH 162/204] Bump io.undertow:undertow-core in /frameworks/Java/undertow Bumps [io.undertow:undertow-core](https://github.com/undertow-io/undertow) from 2.3.14.Final to 2.3.17.Final. - [Release notes](https://github.com/undertow-io/undertow/releases) - [Commits](https://github.com/undertow-io/undertow/compare/2.3.14.Final...2.3.17.Final) --- updated-dependencies: - dependency-name: io.undertow:undertow-core dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- frameworks/Java/undertow/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frameworks/Java/undertow/pom.xml b/frameworks/Java/undertow/pom.xml index da2a6dd086b..133d1ce186c 100644 --- a/frameworks/Java/undertow/pom.xml +++ b/frameworks/Java/undertow/pom.xml @@ -20,7 +20,7 @@ 3.2.2 0.9.10 42.7.2 - 2.3.14.Final + 2.3.17.Final From 7dfbdfc73e2c8dc0099b132e1962a9f6156eada6 Mon Sep 17 00:00:00 2001 From: Petrik de Heus Date: Tue, 22 Oct 2024 16:37:28 +0200 Subject: [PATCH 163/204] [ruby/sinatra] Upgrade Sinatra to v4 (#9347) --- frameworks/Ruby/sinatra-sequel/Gemfile | 2 +- frameworks/Ruby/sinatra-sequel/README.md | 4 ++-- frameworks/Ruby/sinatra/Gemfile | 2 +- frameworks/Ruby/sinatra/README.md | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/frameworks/Ruby/sinatra-sequel/Gemfile b/frameworks/Ruby/sinatra-sequel/Gemfile index f4ac3eb1fe2..4aace641277 100644 --- a/frameworks/Ruby/sinatra-sequel/Gemfile +++ b/frameworks/Ruby/sinatra-sequel/Gemfile @@ -4,7 +4,7 @@ gem 'oj' gem 'passenger', '~> 6.0', :platforms=>[:ruby, :mswin], :require=>false gem 'puma', '~> 6.4', :require=>false gem 'sequel', '~> 5.0' -gem 'sinatra', '~> 3.0', :require=>'sinatra/base' +gem 'sinatra', '~> 4.0', :require=>'sinatra/base' gem 'unicorn', '~> 6.1', :platforms=>[:ruby, :mswin], :require=>false group :mysql do diff --git a/frameworks/Ruby/sinatra-sequel/README.md b/frameworks/Ruby/sinatra-sequel/README.md index 147e20cb2ed..9f382526d82 100644 --- a/frameworks/Ruby/sinatra-sequel/README.md +++ b/frameworks/Ruby/sinatra-sequel/README.md @@ -15,9 +15,9 @@ The tests will be run with: * [Ruby 3.3](http://www.ruby-lang.org) * [JRuby 9.4](http://jruby.org) * [Puma 6](http://puma.io) -* [Passenger 5](https://www.phusionpassenger.com) +* [Passenger 6](https://www.phusionpassenger.com) * [Unicorn 5](https://bogomips.org/unicorn/) -* [Sinatra 3](http://www.sinatrarb.com) +* [Sinatra 4](http://www.sinatrarb.com) * [Sequel 5](http://sequel.jeremyevans.net) * [Slim 3](http://slim-lang.com) * [MySQL 5.5](https://www.mysql.com) diff --git a/frameworks/Ruby/sinatra/Gemfile b/frameworks/Ruby/sinatra/Gemfile index ff34570a2cb..b7db27d395f 100644 --- a/frameworks/Ruby/sinatra/Gemfile +++ b/frameworks/Ruby/sinatra/Gemfile @@ -4,7 +4,7 @@ gem 'activerecord', '~> 7.1', require: 'active_record' gem 'oj' gem 'passenger', '~> 6.0', platforms: [:ruby, :mswin], require: false gem 'puma', '~> 6.4', require: false -gem 'sinatra', '~> 3.0', require: 'sinatra/base' +gem 'sinatra', '~> 4.0', require: 'sinatra/base' gem 'unicorn', '~> 6.1', platforms: [:ruby, :mswin], require: false group :mysql do diff --git a/frameworks/Ruby/sinatra/README.md b/frameworks/Ruby/sinatra/README.md index ff118f6ff21..e0f14b9a171 100644 --- a/frameworks/Ruby/sinatra/README.md +++ b/frameworks/Ruby/sinatra/README.md @@ -16,7 +16,7 @@ The tests will be run with: * [Puma 6](http://puma.io) * [Passenger 6](https://www.phusionpassenger.com) * [Unicorn 6](https://bogomips.org/unicorn/) -* [Sinatra 3](http://www.sinatrarb.com) +* [Sinatra 4](http://www.sinatrarb.com) * [ActiveRecord 7](https://github.com/rails/rails/tree/master/activerecord) * [MySQL 5.5](https://www.mysql.com) * [Postgres 9.3](https://www.postgresql.org) From e2c0eecfb9b0e5d34e12b674e7ddaa4c1c2cd751 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 22 Oct 2024 14:38:14 +0000 Subject: [PATCH 164/204] Bump io.undertow:undertow-core in /frameworks/Java/undertow-jersey Bumps [io.undertow:undertow-core](https://github.com/undertow-io/undertow) from 2.3.16.Final to 2.3.17.Final. - [Release notes](https://github.com/undertow-io/undertow/releases) - [Commits](https://github.com/undertow-io/undertow/compare/2.3.16.Final...2.3.17.Final) --- updated-dependencies: - dependency-name: io.undertow:undertow-core dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- frameworks/Java/undertow-jersey/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frameworks/Java/undertow-jersey/pom.xml b/frameworks/Java/undertow-jersey/pom.xml index 6c2ced9b7a1..af553eea552 100644 --- a/frameworks/Java/undertow-jersey/pom.xml +++ b/frameworks/Java/undertow-jersey/pom.xml @@ -174,7 +174,7 @@ io.undertow undertow-core - 2.3.16.Final + 2.3.17.Final From 920ec79bd8f05447519290d61b504b7f8641dc8a Mon Sep 17 00:00:00 2001 From: Redkale Date: Tue, 22 Oct 2024 22:42:10 +0800 Subject: [PATCH 165/204] Remove redkale-graalvm (#9346) --- frameworks/Java/redkale/BenchmarkService.java | 78 ------------------- frameworks/Java/redkale/benchmark_config.json | 46 ----------- frameworks/Java/redkale/config.toml | 34 -------- frameworks/Java/redkale/pom-jdbc.xml | 2 +- frameworks/Java/redkale/pom.xml | 2 + .../Java/redkale/redkale-block.dockerfile | 17 ---- .../Java/redkale/redkale-graalvm.dockerfile | 16 ---- .../Java/redkale/redkale-jdbc.dockerfile | 3 +- .../Java/redkale/redkale-pgclient.dockerfile | 2 +- frameworks/Java/redkale/redkale.dockerfile | 2 +- 10 files changed, 6 insertions(+), 196 deletions(-) delete mode 100644 frameworks/Java/redkale/BenchmarkService.java delete mode 100644 frameworks/Java/redkale/redkale-block.dockerfile delete mode 100644 frameworks/Java/redkale/redkale-graalvm.dockerfile diff --git a/frameworks/Java/redkale/BenchmarkService.java b/frameworks/Java/redkale/BenchmarkService.java deleted file mode 100644 index 558cbe2fbb2..00000000000 --- a/frameworks/Java/redkale/BenchmarkService.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. - */ -package org.redkalex.benchmark; - -import java.util.*; -import java.util.concurrent.ThreadLocalRandom; -import java.util.stream.Stream; -import org.redkale.annotation.*; -import org.redkale.net.http.*; -import org.redkale.service.AbstractService; -import org.redkale.source.DataSource; - -/** - * 测试redkale-jdbc, 需要覆盖到原BenchmarkService - * - * @author zhangjx - */ -@RestService(name = " ", repair = false) -public class BenchmarkService extends AbstractService { - - private static final byte[] helloBytes = "Hello, world!".getBytes(); - - @Resource - private DataSource source; - - @NonBlocking - @RestMapping(auth = false) - public byte[] plaintext() { - return helloBytes; - } - - @NonBlocking - @RestMapping(auth = false) - public Message json() { - return new Message("Hello, World!"); - } - - @RestMapping(auth = false) - public World db() { - return source.find(World.class, ThreadLocalRandom.current().nextInt(10000) + 1); - } - - @RestMapping(auth = false) - public List queries(int q) { - return source.findsList(World.class, random(q)); - } - - @RestMapping(auth = false) - public List updates(int q) { - int size = Math.min(500, Math.max(1, q)); - int[] newNumbers = ThreadLocalRandom.current().ints(size, 1, 10001).toArray(); - List words = source.findsList(World.class, random(q)); - source.update(World.updateNewNumbers(words, newNumbers)); - return words; - } - - @RestMapping(auth = false) - public HttpScope fortunes() { - List fortunes = source.queryList(Fortune.class); - fortunes.add(new Fortune(0, "Additional fortune added at request time.")); - Collections.sort(fortunes); - return HttpScope.refer("").referObj(fortunes); - } - - @NonBlocking - @RestMapping(name = "cached-worlds", auth = false) - public CachedWorld[] cachedWorlds(int q) { - return source.finds(CachedWorld.class, random(q)); - } - - private Stream random(int q) { - int size = Math.min(500, Math.max(1, q)); - return ThreadLocalRandom.current().ints(size, 1, 10001).boxed(); - } -} diff --git a/frameworks/Java/redkale/benchmark_config.json b/frameworks/Java/redkale/benchmark_config.json index 2371e0e2bec..52f8550ce9f 100644 --- a/frameworks/Java/redkale/benchmark_config.json +++ b/frameworks/Java/redkale/benchmark_config.json @@ -26,30 +26,6 @@ "notes": "", "versus": "Redkale" }, - "graalvm": { - "plaintext_url": "/plaintext", - "json_url": "/json", - "db_url": "/db", - "query_url": "/queries?q=", - "fortune_url": "/fortunes", - "update_url": "/updates?q=", - "cached_query_url": "/cached-worlds?q=", - "port": 8080, - "approach": "Realistic", - "classification": "Fullstack", - "database": "Postgres", - "framework": "Redkale", - "language": "Java", - "flavor": "None", - "orm": "Raw", - "platform": "Redkale", - "webserver": "Redkale", - "os": "Linux", - "database_os": "Linux", - "display_name": "redkale-graalvm", - "notes": "", - "versus": "Redkale" - }, "native": { "plaintext_url": "/plaintext", "json_url": "/json", @@ -95,28 +71,6 @@ "notes": "", "versus": "Redkale" }, - "block": { - "plaintext_url": "/plaintext", - "db_url": "/db", - "query_url": "/queries?q=", - "fortune_url": "/fortunes", - "update_url": "/updates?q=", - "port": 8080, - "approach": "Realistic", - "classification": "Fullstack", - "database": "Postgres", - "framework": "Redkale", - "language": "Java", - "flavor": "None", - "orm": "Raw", - "platform": "Redkale", - "webserver": "Redkale", - "os": "Linux", - "database_os": "Linux", - "display_name": "redkale-block", - "notes": "", - "versus": "Redkale" - }, "pgclient": { "db_url": "/db", "query_url": "/queries?q=", diff --git a/frameworks/Java/redkale/config.toml b/frameworks/Java/redkale/config.toml index 96d8a7f4bf8..149aaad007e 100644 --- a/frameworks/Java/redkale/config.toml +++ b/frameworks/Java/redkale/config.toml @@ -19,24 +19,6 @@ platform = "Redkale" webserver = "Redkale" versus = "Redkale" -[graalvm] -urls.plaintext = "/plaintext" -urls.json = "/json" -urls.db = "/db" -urls.fortune = "/fortunes" -urls.query = "/queries?q=" -urls.update = "/updates?q=" -urls.cached_query = "/cached-worlds?q=" -approach = "Realistic" -classification = "Fullstack" -database = "Postgres" -database_os = "Linux" -os = "Linux" -orm = "Raw" -platform = "Redkale" -webserver = "Redkale" -versus = "Redkale" - [native] urls.plaintext = "/plaintext" urls.json = "/json" @@ -70,22 +52,6 @@ platform = "Redkale" webserver = "Redkale" versus = "Redkale" -[block] -urls.plaintext = "/plaintext" -urls.db = "/db" -urls.fortune = "/fortunes" -urls.query = "/queries?q=" -urls.update = "/updates?q=" -approach = "Realistic" -classification = "Fullstack" -database = "Postgres" -database_os = "Linux" -os = "Linux" -orm = "Raw" -platform = "Redkale" -webserver = "Redkale" -versus = "Redkale" - [pgclient] urls.db = "/db" urls.fortune = "/fortunes" diff --git a/frameworks/Java/redkale/pom-jdbc.xml b/frameworks/Java/redkale/pom-jdbc.xml index e617e4e4059..86b6c6d5fd6 100644 --- a/frameworks/Java/redkale/pom-jdbc.xml +++ b/frameworks/Java/redkale/pom-jdbc.xml @@ -8,7 +8,7 @@ org.redkale.boot.Application 2.8.0-SNAPSHOT - 1.3.0-SNAPSHOT + 1.2.0-SNAPSHOT 42.7.2 UTF-8 21 diff --git a/frameworks/Java/redkale/pom.xml b/frameworks/Java/redkale/pom.xml index 8844a8b7aff..3c7970fb4e3 100644 --- a/frameworks/Java/redkale/pom.xml +++ b/frameworks/Java/redkale/pom.xml @@ -79,6 +79,8 @@ --no-fallback + -J-XX:+UseNUMA + -J-XX:+UseParallelGC diff --git a/frameworks/Java/redkale/redkale-block.dockerfile b/frameworks/Java/redkale/redkale-block.dockerfile deleted file mode 100644 index 55e13c76b73..00000000000 --- a/frameworks/Java/redkale/redkale-block.dockerfile +++ /dev/null @@ -1,17 +0,0 @@ -FROM maven:3.9.6-amazoncorretto-21-debian as maven -WORKDIR /redkale -COPY src src -COPY conf conf -COPY pom.xml pom.xml -COPY BenchmarkService.java src/main/java/org/redkalex/benchmark/BenchmarkService.java -RUN mvn package -q - -FROM openjdk:23-jdk-slim -WORKDIR /redkale -COPY conf conf -RUN sed -i 's/sameHeader="true"/ /g' /redkale/conf/application.xml -COPY --from=maven /redkale/target/redkale-benchmark-1.0.0.jar redkale-benchmark.jar - -EXPOSE 8080 - -CMD ["java", "-server", "-XX:+UseNUMA", "-XX:+UseParallelGC", "-DAPP_HOME=./", "-jar", "redkale-benchmark.jar"] \ No newline at end of file diff --git a/frameworks/Java/redkale/redkale-graalvm.dockerfile b/frameworks/Java/redkale/redkale-graalvm.dockerfile deleted file mode 100644 index 0e3a9a4a597..00000000000 --- a/frameworks/Java/redkale/redkale-graalvm.dockerfile +++ /dev/null @@ -1,16 +0,0 @@ -FROM maven:3.9.6-amazoncorretto-21-debian as maven -WORKDIR /redkale -COPY src src -COPY conf conf -COPY pom.xml pom.xml -RUN mvn package -q - - -FROM ghcr.io/graalvm/jdk-community:22.0.2 -WORKDIR /redkale -COPY conf conf -COPY --from=maven /redkale/target/redkale-benchmark-1.0.0.jar redkale-benchmark.jar - -EXPOSE 8080 - -CMD ["java", "-server", "-XX:+UseNUMA", "-XX:+UseParallelGC", "-DAPP_HOME=./", "-jar", "redkale-benchmark.jar"] diff --git a/frameworks/Java/redkale/redkale-jdbc.dockerfile b/frameworks/Java/redkale/redkale-jdbc.dockerfile index b39997adf5f..ac3a85bec8b 100644 --- a/frameworks/Java/redkale/redkale-jdbc.dockerfile +++ b/frameworks/Java/redkale/redkale-jdbc.dockerfile @@ -3,7 +3,6 @@ WORKDIR /redkale COPY src src COPY conf conf COPY pom-jdbc.xml pom.xml -COPY BenchmarkService.java src/main/java/org/redkalex/benchmark/BenchmarkService.java RUN mvn package -q FROM openjdk:23-jdk-slim @@ -13,4 +12,4 @@ COPY --from=maven /redkale/target/redkale-benchmark-1.0.0.jar redkale-benchmark. EXPOSE 8080 -CMD ["java", "-server", "-XX:+UseNUMA", "-XX:+UseParallelGC", "-DAPP_HOME=./", "-jar", "redkale-benchmark.jar"] \ No newline at end of file +CMD ["java", "-XX:+UseNUMA", "-XX:+UseParallelGC", "-DAPP_HOME=./", "-jar", "redkale-benchmark.jar"] \ No newline at end of file diff --git a/frameworks/Java/redkale/redkale-pgclient.dockerfile b/frameworks/Java/redkale/redkale-pgclient.dockerfile index 6da37e715c5..af47b952c72 100644 --- a/frameworks/Java/redkale/redkale-pgclient.dockerfile +++ b/frameworks/Java/redkale/redkale-pgclient.dockerfile @@ -12,4 +12,4 @@ COPY --from=maven /redkale/target/redkale-benchmark-1.0.0.jar redkale-benchmark. EXPOSE 8080 -CMD ["java", "-server", "-XX:+UseNUMA", "-XX:+UseParallelGC", "-DAPP_HOME=./", "-jar", "redkale-benchmark.jar"] \ No newline at end of file +CMD ["java", "-XX:+UseNUMA", "-XX:+UseParallelGC", "-DAPP_HOME=./", "-jar", "redkale-benchmark.jar"] \ No newline at end of file diff --git a/frameworks/Java/redkale/redkale.dockerfile b/frameworks/Java/redkale/redkale.dockerfile index 4bb09a8dd56..79ec585c205 100644 --- a/frameworks/Java/redkale/redkale.dockerfile +++ b/frameworks/Java/redkale/redkale.dockerfile @@ -12,4 +12,4 @@ COPY --from=maven /redkale/target/redkale-benchmark-1.0.0.jar redkale-benchmark. EXPOSE 8080 -CMD ["java", "-server", "-XX:+UseNUMA", "-XX:+UseParallelGC", "-DAPP_HOME=./", "-jar", "redkale-benchmark.jar"] +CMD ["java", "-XX:+UseNUMA", "-XX:+UseParallelGC", "-DAPP_HOME=./", "-jar", "redkale-benchmark.jar"] From 8e053f0514bba3b2a92b3ac4fc0c21af63c1b6d9 Mon Sep 17 00:00:00 2001 From: Andrew James <59655451+andrew-james-dev@users.noreply.github.com> Date: Tue, 22 Oct 2024 15:42:24 +0100 Subject: [PATCH 166/204] perf: remove arc used in cached query test to increase performance (#9343) --- frameworks/Rust/axum/src/main_sqlx.rs | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/frameworks/Rust/axum/src/main_sqlx.rs b/frameworks/Rust/axum/src/main_sqlx.rs index d10b1ea99ef..163372b83d8 100644 --- a/frameworks/Rust/axum/src/main_sqlx.rs +++ b/frameworks/Rust/axum/src/main_sqlx.rs @@ -1,8 +1,6 @@ mod common; mod sqlx; -use std::sync::Arc; - use ::sqlx::PgPool; use axum::{ extract::{Query, State}, @@ -98,7 +96,7 @@ async fn cache( ) -> impl IntoResponse { let count = parse_params(params); let mut rng = SmallRng::from_rng(&mut thread_rng()).unwrap(); - let mut worlds: Vec>> = Vec::with_capacity(count); + let mut worlds: Vec> = Vec::with_capacity(count); for id in random_ids(&mut rng, count) { worlds.push(cache.get(&id).await); @@ -115,14 +113,15 @@ async fn preload_cache(AppState { db, cache }: &AppState) { .expect("error loading worlds"); for world in worlds { - cache.insert(world.id, Arc::new(world)).await; + cache.insert(world.id, world).await; } } +/// Application state #[derive(Clone)] struct AppState { db: PgPool, - cache: Cache>, + cache: Cache, } #[tokio::main] @@ -135,7 +134,10 @@ async fn main() { let state = AppState { db: create_pool(database_url, max_pool_size, min_pool_size).await, - cache: Cache::new(10000), + cache: Cache::builder() + .initial_capacity(10000) + .max_capacity(10000) + .build() }; // Prime the cache with CachedWorld objects From 25b97fdb7a46bef800b690d3ba861d9e1535194b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Deleuze?= Date: Tue, 22 Oct 2024 16:42:42 +0200 Subject: [PATCH 167/204] Leverage R2BDC recent optimizations (#9341) Should improve some DB tests very significantly under high load! --- frameworks/Java/spring-webflux/pom.xml | 2 ++ .../repository/R2dbcDbRepository.java | 19 ++++--------------- 2 files changed, 6 insertions(+), 15 deletions(-) diff --git a/frameworks/Java/spring-webflux/pom.xml b/frameworks/Java/spring-webflux/pom.xml index 500e9fc8e07..7e1b6865d2d 100644 --- a/frameworks/Java/spring-webflux/pom.xml +++ b/frameworks/Java/spring-webflux/pom.xml @@ -19,6 +19,8 @@ 21 1.3.6 + 1.0.2.RELEASE + 1.0.7.RELEASE diff --git a/frameworks/Java/spring-webflux/src/main/java/benchmark/repository/R2dbcDbRepository.java b/frameworks/Java/spring-webflux/src/main/java/benchmark/repository/R2dbcDbRepository.java index 3cbf5f66d4a..c2524f07862 100644 --- a/frameworks/Java/spring-webflux/src/main/java/benchmark/repository/R2dbcDbRepository.java +++ b/frameworks/Java/spring-webflux/src/main/java/benchmark/repository/R2dbcDbRepository.java @@ -6,8 +6,6 @@ import benchmark.model.Fortune; import benchmark.model.World; -import io.r2dbc.spi.Connection; -import io.r2dbc.spi.ConnectionFactory; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; @@ -16,12 +14,9 @@ public class R2dbcDbRepository implements DbRepository { private final DatabaseClient databaseClient; - private final ConnectionFactory connectionFactory; - private final ThreadLocal> conn = new ThreadLocal<>(); public R2dbcDbRepository(DatabaseClient databaseClient) { this.databaseClient = databaseClient; - this.connectionFactory = databaseClient.getConnectionFactory(); } @Override @@ -54,16 +49,10 @@ public Mono findAndUpdateWorld(int id, int randomNumber) { @Override public Flux fortunes() { - return getConnection() - .flatMapMany(conn -> conn.createStatement("SELECT id, message FROM " + "fortune").execute()) - .flatMap(result -> result.map(r -> new Fortune(r.get(0, Integer.class), r.get(1, String.class)))); - } - - private Mono getConnection() { - if (this.conn.get() == null) { - this.conn.set(Mono.from(connectionFactory.create()).cache()); - } - return this.conn.get(); + return databaseClient + .sql("SELECT id, message FROM fortune") + .mapProperties(Fortune.class) + .all(); } } \ No newline at end of file From 2f858b0951cff13e9818480f9e81e658cd8f7b42 Mon Sep 17 00:00:00 2001 From: Sanskar Jethi <29942790+sansyrox@users.noreply.github.com> Date: Tue, 22 Oct 2024 15:42:55 +0100 Subject: [PATCH 168/204] chore: update robyn (#9340) --- frameworks/Python/robyn/app-const.py | 4 ++-- frameworks/Python/robyn/app.py | 4 ++-- frameworks/Python/robyn/requirements-const.txt | 2 +- frameworks/Python/robyn/requirements.txt | 2 +- frameworks/Python/robyn/robyn-const.dockerfile | 2 +- frameworks/Python/robyn/robyn.dockerfile | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/frameworks/Python/robyn/app-const.py b/frameworks/Python/robyn/app-const.py index 4b806389fa5..ceec8488829 100755 --- a/frameworks/Python/robyn/app-const.py +++ b/frameworks/Python/robyn/app-const.py @@ -8,8 +8,8 @@ class SpecialConfig(Config): def __init__(self): super().__init__() - self.workers = (os.cpu_count() * 2) + 1 - self.processes = os.cpu_count() + self.workers = 2 + self.processes = ( os.cpu_count() * 2 ) + 1 self.log_level = "WARN" diff --git a/frameworks/Python/robyn/app.py b/frameworks/Python/robyn/app.py index e8c975e530f..bbbb037868a 100755 --- a/frameworks/Python/robyn/app.py +++ b/frameworks/Python/robyn/app.py @@ -8,8 +8,8 @@ class SpecialConfig(Config): def __init__(self): super().__init__() - self.workers = (os.cpu_count() * 2) + 1 - self.processes = os.cpu_count() + self.workers = 2 + self.processes = ( os.cpu_count() * 2 ) + 1 self.log_level = "WARN" diff --git a/frameworks/Python/robyn/requirements-const.txt b/frameworks/Python/robyn/requirements-const.txt index fbb88344955..484d4b7704f 100644 --- a/frameworks/Python/robyn/requirements-const.txt +++ b/frameworks/Python/robyn/requirements-const.txt @@ -1,2 +1,2 @@ uvloop==0.19.0 -robyn==0.60.2 +robyn==0.62.0 diff --git a/frameworks/Python/robyn/requirements.txt b/frameworks/Python/robyn/requirements.txt index fbb88344955..484d4b7704f 100644 --- a/frameworks/Python/robyn/requirements.txt +++ b/frameworks/Python/robyn/requirements.txt @@ -1,2 +1,2 @@ uvloop==0.19.0 -robyn==0.60.2 +robyn==0.62.0 diff --git a/frameworks/Python/robyn/robyn-const.dockerfile b/frameworks/Python/robyn/robyn-const.dockerfile index 90b201eccff..9429ff37376 100644 --- a/frameworks/Python/robyn/robyn-const.dockerfile +++ b/frameworks/Python/robyn/robyn-const.dockerfile @@ -8,4 +8,4 @@ RUN pip3 install -r /robyn/requirements-const.txt EXPOSE 8080 -CMD ["robyn", "app-const.py", "--fast"] +CMD ["python", "app-const.py", "--log-level", "warn"] diff --git a/frameworks/Python/robyn/robyn.dockerfile b/frameworks/Python/robyn/robyn.dockerfile index 8de6fea2c19..bc42b5be462 100644 --- a/frameworks/Python/robyn/robyn.dockerfile +++ b/frameworks/Python/robyn/robyn.dockerfile @@ -8,4 +8,4 @@ RUN pip3 install -r /robyn/requirements.txt EXPOSE 8080 -CMD ["robyn", "app.py", "--fast"] +CMD ["python", "app.py", "--log-level", "warn"] From e5cffb4bc1c96846eb240b71615724c6900194e0 Mon Sep 17 00:00:00 2001 From: Petrik de Heus Date: Tue, 22 Oct 2024 16:43:12 +0200 Subject: [PATCH 169/204] [rails] Add Falcon benchmarks (#9339) Falcon is an async server for Ruby. --- frameworks/Ruby/rails/Gemfile | 3 +- frameworks/Ruby/rails/Gemfile.lock | 94 ++++++++++++++++--- frameworks/Ruby/rails/benchmark_config.json | 22 +++++ frameworks/Ruby/rails/config/application.rb | 2 + .../Ruby/rails/config/falcon_preload.rb | 3 + frameworks/Ruby/rails/falcon.rb | 12 +++ frameworks/Ruby/rails/rails-falcon.dockerfile | 26 +++++ frameworks/Ruby/rails/rails.dockerfile | 2 +- frameworks/Ruby/rails/run-with-redis.sh | 2 +- 9 files changed, 152 insertions(+), 14 deletions(-) create mode 100644 frameworks/Ruby/rails/config/falcon_preload.rb create mode 100644 frameworks/Ruby/rails/falcon.rb create mode 100644 frameworks/Ruby/rails/rails-falcon.dockerfile diff --git a/frameworks/Ruby/rails/Gemfile b/frameworks/Ruby/rails/Gemfile index 8039ed09fd9..e5d6e743679 100644 --- a/frameworks/Ruby/rails/Gemfile +++ b/frameworks/Ruby/rails/Gemfile @@ -2,7 +2,8 @@ source 'https://rubygems.org' gem 'oj', '~> 3.16' gem 'pg', '~> 1.5', group: :postgresql -gem 'puma', '~> 6.4' +gem 'puma', '~> 6.4', require: false +gem 'falcon', '~> 0.47', require: false gem 'rails', '~> 7.2.0' gem 'redis', '~> 5.0' gem 'trilogy', '~> 2.8.1', group: :mysql diff --git a/frameworks/Ruby/rails/Gemfile.lock b/frameworks/Ruby/rails/Gemfile.lock index d92307f837d..311ffc7f814 100644 --- a/frameworks/Ruby/rails/Gemfile.lock +++ b/frameworks/Ruby/rails/Gemfile.lock @@ -71,23 +71,73 @@ GEM minitest (>= 5.1) securerandom (>= 0.3) tzinfo (~> 2.0, >= 2.0.5) + async (2.17.0) + console (~> 1.26) + fiber-annotation + io-event (~> 1.6, >= 1.6.5) + async-container (0.18.3) + async (~> 2.10) + async-http (0.82.1) + async (>= 2.10.2) + async-pool (~> 0.9) + io-endpoint (~> 0.14) + io-stream (~> 0.6) + metrics (~> 0.12) + protocol-http (~> 0.37) + protocol-http1 (>= 0.28.1) + protocol-http2 (~> 0.19) + traces (~> 0.10) + async-http-cache (0.4.4) + async-http (~> 0.56) + async-pool (0.10.1) + async (>= 1.25) + traces + async-service (0.12.0) + async + async-container (~> 0.16) base64 (0.2.0) bigdecimal (3.1.8) builder (3.3.0) concurrent-ruby (1.3.4) connection_pool (2.4.1) + console (1.27.0) + fiber-annotation + fiber-local (~> 1.1) + json crass (1.0.6) date (3.3.4) drb (2.2.1) erubi (1.13.0) + falcon (0.48.3) + async + async-container (~> 0.18) + async-http (~> 0.75) + async-http-cache (~> 0.4) + async-service (~> 0.10) + bundler + localhost (~> 1.1) + openssl (~> 3.0) + process-metrics (~> 0.2) + protocol-http (~> 0.31) + protocol-rack (~> 0.7) + samovar (~> 2.3) + fiber-annotation (0.2.0) + fiber-local (1.1.0) + fiber-storage + fiber-storage (1.0.0) globalid (1.2.1) activesupport (>= 6.1) i18n (1.14.6) concurrent-ruby (~> 1.0) io-console (0.7.2) - irb (1.14.0) + io-endpoint (0.14.0) + io-event (1.7.2) + io-stream (0.6.0) + irb (1.14.1) rdoc (>= 4.0.0) reline (>= 0.4.2) + json (2.7.2) + localhost (1.3.1) logger (1.6.1) loofah (2.22.0) crass (~> 1.0.2) @@ -97,11 +147,13 @@ GEM net-imap net-pop net-smtp + mapping (1.1.1) marcel (1.0.4) + metrics (0.12.0) mini_mime (1.1.5) mini_portile2 (2.8.7) minitest (5.25.1) - net-imap (0.4.14) + net-imap (0.4.17) date net-protocol net-pop (0.1.2) @@ -118,14 +170,29 @@ GEM racc (~> 1.4) nokogiri (1.16.7-x86_64-linux) racc (~> 1.4) - oj (3.16.5) + oj (3.16.6) bigdecimal (>= 3.0) ostruct (>= 0.2) + openssl (3.2.0) ostruct (0.6.0) - pg (1.5.7) + pg (1.5.8) + process-metrics (0.3.0) + console (~> 1.8) + json (~> 2) + samovar (~> 2.1) + protocol-hpack (1.5.1) + protocol-http (0.40.0) + protocol-http1 (0.28.1) + protocol-http (~> 0.22) + protocol-http2 (0.19.3) + protocol-hpack (~> 1.4) + protocol-http (~> 0.18) + protocol-rack (0.10.1) + protocol-http (~> 0.37) + rack (>= 1.0) psych (5.1.2) stringio - puma (6.4.2) + puma (6.4.3) nio4r (~> 2.0) racc (1.8.1) rack (3.1.8) @@ -168,27 +235,31 @@ GEM rake (13.2.1) rdoc (6.7.0) psych (>= 4.0.0) - redis (5.2.0) + redis (5.3.0) redis-client (>= 0.22.0) redis-client (0.22.2) connection_pool - reline (0.5.9) + reline (0.5.10) io-console (~> 0.5) + samovar (2.3.0) + console (~> 1.0) + mapping (~> 1.0) securerandom (0.3.1) stringio (3.1.1) - thor (1.3.1) + thor (1.3.2) timeout (0.4.1) + traces (0.13.1) trilogy (2.8.1) tzinfo (2.0.6) concurrent-ruby (~> 1.0) - tzinfo-data (1.2024.1) + tzinfo-data (1.2024.2) tzinfo (>= 1.0.0) useragent (0.16.10) - webrick (1.8.1) + webrick (1.8.2) websocket-driver (0.7.6) websocket-extensions (>= 0.1.0) websocket-extensions (0.1.5) - zeitwerk (2.6.17) + zeitwerk (2.7.0) PLATFORMS arm64-darwin-20 @@ -196,6 +267,7 @@ PLATFORMS x86_64-linux DEPENDENCIES + falcon (~> 0.47) oj (~> 3.16) pg (~> 1.5) puma (~> 6.4) diff --git a/frameworks/Ruby/rails/benchmark_config.json b/frameworks/Ruby/rails/benchmark_config.json index 7e309e25450..c5562485d6f 100644 --- a/frameworks/Ruby/rails/benchmark_config.json +++ b/frameworks/Ruby/rails/benchmark_config.json @@ -44,6 +44,28 @@ "display_name": "rails-mysql", "notes": "", "versus": "rack-puma-mri" + }, + "falcon": { + "db_url": "/db", + "json_url": "/json", + "query_url": "/queries?queries=", + "fortune_url": "/fortunes", + "update_url": "/updates?queries=", + "plaintext_url": "/plaintext", + "port": 8080, + "approach": "Realistic", + "classification": "Fullstack", + "database": "Postgres", + "framework": "rails", + "language": "Ruby", + "orm": "Full", + "platform": "Rack", + "webserver": "Falcon", + "os": "Linux", + "database_os": "Linux", + "display_name": "rails-falcon", + "notes": "", + "versus": "rack-falcon-mri" } }] } diff --git a/frameworks/Ruby/rails/config/application.rb b/frameworks/Ruby/rails/config/application.rb index 75a12720345..291c4f983ae 100644 --- a/frameworks/Ruby/rails/config/application.rb +++ b/frameworks/Ruby/rails/config/application.rb @@ -51,5 +51,7 @@ class Application < Rails::Application config.middleware.delete Rack::Sendfile config.middleware.delete Rack::TempfileReaper config.middleware.delete Rails::Rack::Logger + + config.active_support.isolation_level = :fiber if defined?(Falcon) end end diff --git a/frameworks/Ruby/rails/config/falcon_preload.rb b/frameworks/Ruby/rails/config/falcon_preload.rb new file mode 100644 index 00000000000..647c7b948d9 --- /dev/null +++ b/frameworks/Ruby/rails/config/falcon_preload.rb @@ -0,0 +1,3 @@ +# required by Falcon: +# https://github.com/socketry/falcon/blob/19fe8ece7cc49aa03222afe2c940682aeb69fe37/guides/rails-integration/readme.md?plain=1#L38 +require_relative "../config/environment" diff --git a/frameworks/Ruby/rails/falcon.rb b/frameworks/Ruby/rails/falcon.rb new file mode 100644 index 00000000000..147d6b3b66f --- /dev/null +++ b/frameworks/Ruby/rails/falcon.rb @@ -0,0 +1,12 @@ +#!/usr/bin/env -S falcon host +# frozen_string_literal: true + +load :rack + +hostname = File.basename(__dir__) +port = ENV["PORT"] || 8080 + +rack hostname do + append preload "config/falcon_preload.rb" + endpoint Async::HTTP::Endpoint.parse("http://0.0.0.0:#{port}") +end diff --git a/frameworks/Ruby/rails/rails-falcon.dockerfile b/frameworks/Ruby/rails/rails-falcon.dockerfile new file mode 100644 index 00000000000..3244b73aa02 --- /dev/null +++ b/frameworks/Ruby/rails/rails-falcon.dockerfile @@ -0,0 +1,26 @@ +FROM ruby:3.4-rc + +RUN apt-get update -yqq && apt-get install -yqq --no-install-recommends redis-server + +EXPOSE 8080 +WORKDIR /rails + +# ENV RUBY_YJIT_ENABLE=1 YJIT is enabled in config/initializers/enable_yjit.rb + +# Use Jemalloc +RUN apt-get update && \ + apt-get install -y --no-install-recommends libjemalloc2 +ENV LD_PRELOAD=libjemalloc.so.2 + +COPY ./Gemfile* /rails/ + +ENV BUNDLE_FORCE_RUBY_PLATFORM=true +ENV BUNDLE_WITHOUT=mysql +RUN bundle install --jobs=8 + +COPY . /rails/ + +ENV RAILS_ENV=production_postgresql +ENV PORT=8080 +ENV REDIS_URL=redis://localhost:6379/0 +CMD bundle exec falcon host diff --git a/frameworks/Ruby/rails/rails.dockerfile b/frameworks/Ruby/rails/rails.dockerfile index 392920be9c4..8eb53c4dbd2 100644 --- a/frameworks/Ruby/rails/rails.dockerfile +++ b/frameworks/Ruby/rails/rails.dockerfile @@ -15,7 +15,7 @@ ENV LD_PRELOAD=libjemalloc.so.2 COPY ./Gemfile* /rails/ ENV BUNDLE_FORCE_RUBY_PLATFORM=true -ENV BUNDLE_WITHOUT=trilogy +ENV BUNDLE_WITHOUT=mysql RUN bundle install --jobs=8 COPY . /rails/ diff --git a/frameworks/Ruby/rails/run-with-redis.sh b/frameworks/Ruby/rails/run-with-redis.sh index 9ce9b243b74..036224f0df5 100755 --- a/frameworks/Ruby/rails/run-with-redis.sh +++ b/frameworks/Ruby/rails/run-with-redis.sh @@ -1,3 +1,3 @@ #!/bin/bash service redis-server start -rails server +bundle exec falcon host From 917d50a57592a5978095453280423cbb52cfef1d Mon Sep 17 00:00:00 2001 From: Petrik de Heus Date: Tue, 22 Oct 2024 16:43:25 +0200 Subject: [PATCH 170/204] [rack] Don't install unused servers (#9337) For example, don't install falcon when testing puma. Also use the shorter "Puma" for the 'Server' header when using puma. --- frameworks/Ruby/rack/Gemfile | 15 ++++++++++++--- frameworks/Ruby/rack/hello_world.rb | 4 ++-- frameworks/Ruby/rack/rack-falcon.dockerfile | 4 ++-- frameworks/Ruby/rack/rack-jruby.dockerfile | 2 +- frameworks/Ruby/rack/rack-unicorn.dockerfile | 4 +--- frameworks/Ruby/rack/rack.dockerfile | 5 ++--- 6 files changed, 20 insertions(+), 14 deletions(-) diff --git a/frameworks/Ruby/rack/Gemfile b/frameworks/Ruby/rack/Gemfile index af0fc5b1d04..ab7f29130b7 100644 --- a/frameworks/Ruby/rack/Gemfile +++ b/frameworks/Ruby/rack/Gemfile @@ -4,16 +4,25 @@ source 'https://rubygems.org' gem 'rack', '~> 3.0' gem 'connection_pool', '~> 2.4' -gem 'falcon', '~> 0.47', platforms: %i[ruby mswin] gem 'jdbc-postgres', '~> 42.2', platforms: :jruby, require: 'jdbc/postgres' gem 'json', '~> 2.6', platforms: :jruby gem 'oj', '~> 3.14', platforms: %i[ruby mswin] gem 'pg', '~> 1.5', platforms: %i[ruby mswin] -gem 'puma', '~> 6.4' gem 'sequel' gem 'sequel_pg', platforms: %i[ruby mswin] gem 'tzinfo-data', '1.2023.3' -gem 'unicorn', '~> 6.1', platforms: %i[ruby mswin], require: false + +group :falcon do + gem 'falcon', '~> 0.47', platforms: %i[ruby mswin] +end + +group :puma do + gem 'puma', '~> 6.4' +end + +group :unicorn do + gem 'unicorn', '~> 6.1', platforms: %i[ruby mswin] +end group :development do gem 'rack-test' diff --git a/frameworks/Ruby/rack/hello_world.rb b/frameworks/Ruby/rack/hello_world.rb index 2fcacec605b..050b6eac801 100644 --- a/frameworks/Ruby/rack/hello_world.rb +++ b/frameworks/Ruby/rack/hello_world.rb @@ -30,13 +30,13 @@ class HelloWorld SERVER_STRING = if defined?(PhusionPassenger) 'Passenger' elsif defined?(Puma) - Puma::Const::PUMA_SERVER_STRING + 'Puma' elsif defined?(Unicorn) 'Unicorn' elsif defined?(Falcon) 'Falcon' else - ' Ruby Rack' + 'Ruby Rack' end TEMPLATE_PREFIX = ' diff --git a/frameworks/Ruby/rack/rack-falcon.dockerfile b/frameworks/Ruby/rack/rack-falcon.dockerfile index f6ba1a106a2..f030cd54177 100644 --- a/frameworks/Ruby/rack/rack-falcon.dockerfile +++ b/frameworks/Ruby/rack/rack-falcon.dockerfile @@ -9,10 +9,10 @@ ENV LD_PRELOAD=libjemalloc.so.2 WORKDIR /rack -COPY Gemfile ./ +COPY Gemfile ./ ENV BUNDLE_FORCE_RUBY_PLATFORM=true -RUN bundle config set without 'development test' +RUN bundle config set without 'development test puma unicorn' RUN bundle install --jobs=8 COPY . . diff --git a/frameworks/Ruby/rack/rack-jruby.dockerfile b/frameworks/Ruby/rack/rack-jruby.dockerfile index 7bf4b329af1..ab06ae132ed 100644 --- a/frameworks/Ruby/rack/rack-jruby.dockerfile +++ b/frameworks/Ruby/rack/rack-jruby.dockerfile @@ -6,7 +6,7 @@ WORKDIR /rack COPY Gemfile ./ -RUN bundle config set without 'development test' +RUN bundle config set without 'development test falcon unicorn' RUN bundle install --jobs=8 COPY . . diff --git a/frameworks/Ruby/rack/rack-unicorn.dockerfile b/frameworks/Ruby/rack/rack-unicorn.dockerfile index 8609febfd7b..74b3e82041c 100644 --- a/frameworks/Ruby/rack/rack-unicorn.dockerfile +++ b/frameworks/Ruby/rack/rack-unicorn.dockerfile @@ -12,13 +12,11 @@ WORKDIR /rack COPY Gemfile ./ ENV BUNDLE_FORCE_RUBY_PLATFORM=true -RUN bundle config set without 'development test' +RUN bundle config set without 'development test falcon puma' RUN bundle install --jobs=8 COPY . . EXPOSE 8080 -#CMD nginx -c /rack/config/nginx.conf && bundle exec unicorn -E production -c config/unicorn.rb - CMD bundle exec unicorn -c config/unicorn.rb -o 0.0.0.0 -p 8080 -E production diff --git a/frameworks/Ruby/rack/rack.dockerfile b/frameworks/Ruby/rack/rack.dockerfile index b9b39c43122..615775cf9ea 100644 --- a/frameworks/Ruby/rack/rack.dockerfile +++ b/frameworks/Ruby/rack/rack.dockerfile @@ -10,10 +10,10 @@ ENV LD_PRELOAD=libjemalloc.so.2 WORKDIR /rack -COPY Gemfile ./ +COPY Gemfile ./ ENV BUNDLE_FORCE_RUBY_PLATFORM=true -RUN bundle config set without 'development test' +RUN bundle config set without 'development test falcon unicorn' RUN bundle install --jobs=8 COPY . . @@ -21,4 +21,3 @@ COPY . . EXPOSE 8080 CMD bundle exec puma -C config/puma.rb -b tcp://0.0.0.0:8080 -e production - From 188ddd594ed6743318d2f0f0e8cd0e114429bfdf Mon Sep 17 00:00:00 2001 From: Petrik de Heus Date: Tue, 22 Oct 2024 16:43:36 +0200 Subject: [PATCH 171/204] [ruby/sinatra] Release connection to pool outside block (#9336) ActiveRecord 7.2 introduced ActiveRecord::Base.with_connection which releases the connection after the block has run. This allows us to remove clearing active connections after the request has finished. | |plaintext|update| json| db|query|fortune|weighted_score| |-----------|---------|------|-----|-----|-----|-------|--------------| |master | 73851| 7851|84330|37661|15144| 19934| 1109| |branch | 83429| 8401|91051|41432|14251| 21369| 1147| --- frameworks/Ruby/sinatra/Gemfile | 2 +- frameworks/Ruby/sinatra/hello_world.rb | 25 +++++++++++-------------- 2 files changed, 12 insertions(+), 15 deletions(-) diff --git a/frameworks/Ruby/sinatra/Gemfile b/frameworks/Ruby/sinatra/Gemfile index b7db27d395f..95fe5743580 100644 --- a/frameworks/Ruby/sinatra/Gemfile +++ b/frameworks/Ruby/sinatra/Gemfile @@ -1,6 +1,6 @@ source 'https://rubygems.org' -gem 'activerecord', '~> 7.1', require: 'active_record' +gem 'activerecord', '~> 7.2', require: 'active_record' gem 'oj' gem 'passenger', '~> 6.0', platforms: [:ruby, :mswin], require: false gem 'puma', '~> 6.4', require: false diff --git a/frameworks/Ruby/sinatra/hello_world.rb b/frameworks/Ruby/sinatra/hello_world.rb index 328fa402921..dad43a41c20 100644 --- a/frameworks/Ruby/sinatra/hello_world.rb +++ b/frameworks/Ruby/sinatra/hello_world.rb @@ -39,10 +39,6 @@ def rand1 response['Server'] = SERVER_STRING end if SERVER_STRING - after do - ActiveRecord::Base.connection_handler.clear_active_connections! - end - # Test type 1: JSON serialization get '/json' do json message: 'Hello, World!' @@ -51,7 +47,7 @@ def rand1 # Test type 2: Single database query get '/db' do world = - ActiveRecord::Base.connection_pool.with_connection do + ActiveRecord::Base.with_connection do World.find(rand1).attributes end @@ -61,7 +57,7 @@ def rand1 # Test type 3: Multiple database queries get '/queries' do worlds = - ActiveRecord::Base.connection_pool.with_connection do + ActiveRecord::Base.with_connection do ALL_IDS.sample(bounded_queries).map do |id| World.find(id).attributes end @@ -72,7 +68,7 @@ def rand1 # Test type 4: Fortunes get '/fortunes' do - @fortunes = ActiveRecord::Base.connection_pool.with_connection do + @fortunes = ActiveRecord::Base.with_connection do Fortune.all end.to_a @fortunes << Fortune.new( @@ -86,17 +82,18 @@ def rand1 # Test type 5: Database updates get '/updates' do - worlds = - ALL_IDS.sample(bounded_queries).map do |id| - world = ActiveRecord::Base.connection_pool.with_connection do - World.find(id) - end + worlds = nil + ActiveRecord::Base.with_connection do + worlds = ALL_IDS.sample(bounded_queries).map do |id| + world = World.find(id) new_value = rand1 new_value = rand1 until new_value != world.randomNumber { id: id, randomNumber: new_value } end - ActiveRecord::Base.connection_pool.with_connection do - World.upsert_all(worlds.sort_by!{_1[:id]}) + end + worlds.sort_by!{_1[:id]} + ActiveRecord::Base.with_connection do + World.upsert_all(worlds) end json worlds end From c66c74940d532a54e9a782a2e2134b9859f68fd9 Mon Sep 17 00:00:00 2001 From: Giovanni Barillari Date: Tue, 22 Oct 2024 16:43:49 +0200 Subject: [PATCH 172/204] Bump emmett to 2.6 (#9330) --- frameworks/Python/emmett/app.py | 2 +- frameworks/Python/emmett/requirements.txt | 4 ++-- frameworks/Python/emmett/run.py | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/frameworks/Python/emmett/app.py b/frameworks/Python/emmett/app.py index 50a942ce7ad..7d012fe70b3 100644 --- a/frameworks/Python/emmett/app.py +++ b/frameworks/Python/emmett/app.py @@ -32,7 +32,7 @@ def _serialize(self, row): app.config.db.user = 'benchmarkdbuser' app.config.db.password = 'benchmarkdbpass' app.config.db.database = 'hello_world' -app.config.db.pool_size = 10 +app.config.db.pool_size = 16 db = Database(app) db.define_models(World, Fortune) diff --git a/frameworks/Python/emmett/requirements.txt b/frameworks/Python/emmett/requirements.txt index 627a2187091..1621f272390 100644 --- a/frameworks/Python/emmett/requirements.txt +++ b/frameworks/Python/emmett/requirements.txt @@ -1,2 +1,2 @@ -emmett[orjson]>=2.5.12,<2.6.0 -psycopg2-binary==2.9.5 +emmett[orjson]>=2.6.0,<2.7.0 +psycopg2-binary==2.9.9 diff --git a/frameworks/Python/emmett/run.py b/frameworks/Python/emmett/run.py index 02a21e458f9..aad30c549c6 100644 --- a/frameworks/Python/emmett/run.py +++ b/frameworks/Python/emmett/run.py @@ -1,10 +1,10 @@ import multiprocessing -from emmett.server import run +from emmett_core.server import run if __name__ == "__main__": - workers = round(multiprocessing.cpu_count() / 2) + workers = multiprocessing.cpu_count() run( "rsgi", From 17c1c8deb47ba36dd54c72a12927b9dba6c43608 Mon Sep 17 00:00:00 2001 From: Giovanni Barillari Date: Tue, 22 Oct 2024 16:44:12 +0200 Subject: [PATCH 173/204] [Python] Add emmett55 (#9331) --- frameworks/Python/emmett55/README.md | 26 ++++ frameworks/Python/emmett55/app.py | 129 ++++++++++++++++++ .../Python/emmett55/benchmark_config.json | 27 ++++ frameworks/Python/emmett55/config.toml | 19 +++ .../Python/emmett55/emmett55.dockerfile | 11 ++ frameworks/Python/emmett55/requirements.txt | 3 + frameworks/Python/emmett55/run.py | 20 +++ .../Python/emmett55/templates/fortunes.html | 20 +++ 8 files changed, 255 insertions(+) create mode 100644 frameworks/Python/emmett55/README.md create mode 100644 frameworks/Python/emmett55/app.py create mode 100644 frameworks/Python/emmett55/benchmark_config.json create mode 100644 frameworks/Python/emmett55/config.toml create mode 100644 frameworks/Python/emmett55/emmett55.dockerfile create mode 100644 frameworks/Python/emmett55/requirements.txt create mode 100644 frameworks/Python/emmett55/run.py create mode 100644 frameworks/Python/emmett55/templates/fortunes.html diff --git a/frameworks/Python/emmett55/README.md b/frameworks/Python/emmett55/README.md new file mode 100644 index 00000000000..0e36619cfc8 --- /dev/null +++ b/frameworks/Python/emmett55/README.md @@ -0,0 +1,26 @@ +# Emmett55 Benchmark Test + +This is the Emmett55 portion of a [benchmarking tests suite](../../) comparing a variety of web development platforms. + +The information below is specific to Emmett55. For further guidance, review the [documentation](https://github.com/TechEmpower/FrameworkBenchmarks/wiki). + +Also note that there is additional information provided in the [Python README](../). + +## Description + +[Emmett55](https://github.com/emmett-framework/emmett55) is a Python asyncIO micro web framework. + +## Test Paths & Source + +* [JSON Serialization](app.py): "/json" +* [Single Database Query](app.py): "/db" +* [Multiple Database Queries](app.py): "queries?queries=#" +* [Fortunes](app.py): "/fortunes" +* [Database Updates](app.py): "updates?queries=#" +* [Plaintext](app.py): "/plaintext" + +*Replace # with an actual number.* + +### Resources + +* [Github repository](https://github.com/emmett-framework/emmett55) diff --git a/frameworks/Python/emmett55/app.py b/frameworks/Python/emmett55/app.py new file mode 100644 index 00000000000..e417e8f75fa --- /dev/null +++ b/frameworks/Python/emmett55/app.py @@ -0,0 +1,129 @@ +import os +from operator import itemgetter +from random import randint, sample + +import asyncpg +from emmett55 import App, Pipe, current, request, response +from emmett55.extensions import Extension, Signals, listen_signal +from emmett55.tools import service +from renoir import Renoir + + +class AsyncPG(Extension): + __slots__ = ["pool"] + + def on_load(self): + self.pool = None + self.pipe = AsyncPGPipe(self) + + async def build_pool(self): + self.pool = await asyncpg.create_pool( + user=os.getenv('PGUSER', 'benchmarkdbuser'), + password=os.getenv('PGPASS', 'benchmarkdbpass'), + database='hello_world', + host='tfb-database', + port=5432, + min_size=16, + max_size=16, + max_queries=64_000_000_000, + max_inactive_connection_lifetime=0 + ) + + @listen_signal(Signals.after_loop) + def _init_pool(self, loop): + loop.run_until_complete(self.build_pool()) + + +class AsyncPGPipe(Pipe): + __slots__ = ["ext"] + + def __init__(self, ext): + self.ext = ext + + async def open(self): + conn = current._db_conn = self.ext.pool.acquire() + current.db = await conn.__aenter__() + + async def close(self): + await current._db_conn.__aexit__() + + +app = App(__name__) +app.config.handle_static = False +templates = Renoir() + +db_ext = app.use_extension(AsyncPG) + +SQL_SELECT = 'SELECT "randomnumber", "id" FROM "world" WHERE id = $1' +SQL_UPDATE = 'UPDATE "world" SET "randomnumber"=$1 WHERE id=$2' +ROW_ADD = [0, 'Additional fortune added at request time.'] +sort_key = itemgetter(1) + + +@app.route() +@service.json +async def json(): + return {'message': 'Hello, World!'} + + +@app.route("/db", pipeline=[db_ext.pipe]) +@service.json +async def get_random_world(): + row_id = randint(1, 10000) + number = await current.db.fetchval(SQL_SELECT, row_id) + return {'id': row_id, 'randomNumber': number} + + +def get_qparam(): + try: + rv = int(request.query_params.queries or 1) + except ValueError: + return 1 + if rv < 1: + return 1 + if rv > 500: + return 500 + return rv + + +@app.route("/queries", pipeline=[db_ext.pipe]) +@service.json +async def get_random_worlds(): + num_queries = get_qparam() + row_ids = sample(range(1, 10000), num_queries) + worlds = [] + statement = await current.db.prepare(SQL_SELECT) + for row_id in row_ids: + number = await statement.fetchval(row_id) + worlds.append({'id': row_id, 'randomNumber': number}) + return worlds + + +@app.route(pipeline=[db_ext.pipe], output='str') +async def fortunes(): + response.content_type = "text/html; charset=utf-8" + fortunes = await current.db.fetch('SELECT * FROM Fortune') + fortunes.append(ROW_ADD) + fortunes.sort(key=sort_key) + return templates.render("templates/fortunes.html", {"fortunes": fortunes}) + + +@app.route(pipeline=[db_ext.pipe]) +@service.json +async def updates(): + num_queries = get_qparam() + updates = list(zip( + sample(range(1, 10000), num_queries), + sorted(sample(range(1, 10000), num_queries)) + )) + worlds = [{'id': row_id, 'randomNumber': number} for row_id, number in updates] + statement = await current.db.prepare(SQL_SELECT) + for row_id, _ in updates: + await statement.fetchval(row_id) + await current.db.executemany(SQL_UPDATE, updates) + return worlds + + +@app.route(output='bytes') +async def plaintext(): + return b'Hello, World!' diff --git a/frameworks/Python/emmett55/benchmark_config.json b/frameworks/Python/emmett55/benchmark_config.json new file mode 100644 index 00000000000..e842529efcb --- /dev/null +++ b/frameworks/Python/emmett55/benchmark_config.json @@ -0,0 +1,27 @@ +{ + "framework": "emmett55", + "tests": [{ + "default": { + "json_url": "/json", + "db_url": "/db", + "query_url": "/queries?queries=", + "fortune_url": "/fortunes", + "update_url": "/updates?queries=", + "plaintext_url": "/plaintext", + "port": 8080, + "approach": "Realistic", + "classification": "Micro", + "database": "Postgres", + "framework": "Emmett55", + "language": "Python", + "orm": "Raw", + "platform": "RSGI", + "webserver": "granian", + "os": "Linux", + "database_os": "Linux", + "display_name": "Emmett55", + "notes": "CPython 3.7", + "versus": "uvicorn" + } + }] +} diff --git a/frameworks/Python/emmett55/config.toml b/frameworks/Python/emmett55/config.toml new file mode 100644 index 00000000000..11586c4e530 --- /dev/null +++ b/frameworks/Python/emmett55/config.toml @@ -0,0 +1,19 @@ +[framework] +name = "emmett55" + +[main] +urls.plaintext = "/plaintext" +urls.json = "/json" +urls.db = "/db" +urls.query = "/queries?queries=" +urls.update = "/updates?queries=" +urls.fortune = "/fortunes" +approach = "Realistic" +classification = "Micro" +database = "Postgres" +database_os = "Linux" +os = "Linux" +orm = "Raw" +platform = "RSGI" +webserver = "granian" +versus = "uvicorn" diff --git a/frameworks/Python/emmett55/emmett55.dockerfile b/frameworks/Python/emmett55/emmett55.dockerfile new file mode 100644 index 00000000000..49438fd442d --- /dev/null +++ b/frameworks/Python/emmett55/emmett55.dockerfile @@ -0,0 +1,11 @@ +FROM python:3.11-slim + +ADD ./ /emmett55 + +WORKDIR /emmett55 + +RUN pip install --no-cache-dir -r /emmett55/requirements.txt + +EXPOSE 8080 + +CMD python run.py diff --git a/frameworks/Python/emmett55/requirements.txt b/frameworks/Python/emmett55/requirements.txt new file mode 100644 index 00000000000..ecf2313a108 --- /dev/null +++ b/frameworks/Python/emmett55/requirements.txt @@ -0,0 +1,3 @@ +asyncpg==0.29.0 +emmett55[orjson]>=1.0.0,<1.1.0 +renoir==1.8.0 diff --git a/frameworks/Python/emmett55/run.py b/frameworks/Python/emmett55/run.py new file mode 100644 index 00000000000..aad30c549c6 --- /dev/null +++ b/frameworks/Python/emmett55/run.py @@ -0,0 +1,20 @@ +import multiprocessing + +from emmett_core.server import run + + +if __name__ == "__main__": + workers = multiprocessing.cpu_count() + + run( + "rsgi", + ("app", "app"), + host="0.0.0.0", + port=8080, + workers=workers, + backlog=16384, + threading_mode="runtime", + http="1", + enable_websockets=False, + log_level="warn" + ) diff --git a/frameworks/Python/emmett55/templates/fortunes.html b/frameworks/Python/emmett55/templates/fortunes.html new file mode 100644 index 00000000000..c64ff16ec6f --- /dev/null +++ b/frameworks/Python/emmett55/templates/fortunes.html @@ -0,0 +1,20 @@ + + + + Fortunes + + + + + + + + {{ for fortune in fortunes: }} + + + + + {{ pass }} +
    idmessage
    {{ =fortune[0] }}{{ =fortune[1] }}
    + + From 68e4d14762182ef43e5b05e7a82d35c8df09081e Mon Sep 17 00:00:00 2001 From: MARiA so cute <33935209+NathanFreeman@users.noreply.github.com> Date: Tue, 22 Oct 2024 22:44:25 +0800 Subject: [PATCH 174/204] optimize code (#9335) --- frameworks/PHP/swoole/database.php | 33 +++++-------------- .../PHP/swoole/swoole-async-mysql.dockerfile | 1 - .../swoole/swoole-async-postgres.dockerfile | 1 - .../PHP/swoole/swoole-sync-mysql.dockerfile | 1 - .../swoole/swoole-sync-postgres.dockerfile | 1 - 5 files changed, 8 insertions(+), 29 deletions(-) diff --git a/frameworks/PHP/swoole/database.php b/frameworks/PHP/swoole/database.php index 97d3af6887a..a0c15234921 100644 --- a/frameworks/PHP/swoole/database.php +++ b/frameworks/PHP/swoole/database.php @@ -15,7 +15,7 @@ class Operation public static function db(PDOStatement|PDOStatementProxy $db): string { $db->execute([mt_rand(1, 10000)]); - return json_encode($db->fetch(PDO::FETCH_ASSOC), JSON_NUMERIC_CHECK); + return json_encode($db->fetch(PDO::FETCH_ASSOC)); } public static function fortunes(PDOStatement|PDOStatementProxy $fortune): string @@ -42,7 +42,7 @@ public static function query(PDOStatement|PDOStatementProxy $query, int $queries $results[] = $query->fetch(PDO::FETCH_ASSOC); } - return json_encode($results, JSON_NUMERIC_CHECK); + return json_encode($results); } public static function updates(PDOStatement|PDOStatementProxy $random, PDOStatement|PDOStatementProxy $update, int $queries, string $driver): string @@ -65,7 +65,7 @@ public static function updates(PDOStatement|PDOStatementProxy $random, PDOStatem if ($driver == 'pgsql') { $update->execute([...$values, ...$keys]); } - return json_encode($results, JSON_NUMERIC_CHECK); + return json_encode($results); } } @@ -130,9 +130,6 @@ class Connections { private static PDOPool $pool; private static string $driver; - private static array $dbs = []; - private static array $fortunes = []; - private static array $updates = []; public static function init(string $driver): void { @@ -195,28 +192,14 @@ private static function put(PDO|PDOProxy $db): void private static function getStatement(PDO|PDOProxy $pdo, string $type, int $queries = 0): PDOStatement|PDOStatementProxy { - $hash = spl_object_id($pdo); - if ('select' == $type) { - if (!isset(self::$dbs[$hash])) { - self::$dbs[$hash] = $pdo->prepare(Operation::WORLD_SELECT_SQL); - } - - return self::$dbs[$hash]; + return $pdo->prepare(Operation::WORLD_SELECT_SQL); } elseif ('fortunes' == $type) { - if (!isset(self::$fortunes[$hash])) { - self::$fortunes[$hash] = $pdo->prepare(Operation::FORTUNE_SQL); - } - - return self::$fortunes[$hash]; + return $pdo->prepare(Operation::FORTUNE_SQL); } else { - if (!isset(self::$updates[$hash][$queries])) { - self::$updates[$hash][$queries] = self::$driver == 'pgsql' - ? $pdo->prepare('UPDATE World SET randomNumber = CASE id'.\str_repeat(' WHEN ?::INTEGER THEN ?::INTEGER ', $queries).'END WHERE id IN ('.\str_repeat('?::INTEGER,', $queries - 1).'?::INTEGER)') - : $pdo->prepare(Operation::WORLD_UPDATE_SQL); - } - - return self::$updates[$hash][$queries]; + return self::$driver == 'pgsql' + ? $pdo->prepare('UPDATE World SET randomNumber = CASE id'.\str_repeat(' WHEN ?::INTEGER THEN ?::INTEGER ', $queries).'END WHERE id IN ('.\str_repeat('?::INTEGER,', $queries - 1).'?::INTEGER)') + : $pdo->prepare(Operation::WORLD_UPDATE_SQL); } } } diff --git a/frameworks/PHP/swoole/swoole-async-mysql.dockerfile b/frameworks/PHP/swoole/swoole-async-mysql.dockerfile index b9ce354edb2..9e5e1882565 100644 --- a/frameworks/PHP/swoole/swoole-async-mysql.dockerfile +++ b/frameworks/PHP/swoole/swoole-async-mysql.dockerfile @@ -25,7 +25,6 @@ RUN apt update -yqq > /dev/null \ WORKDIR /swoole ADD ./swoole-server.php /swoole -ADD 10-opcache.ini /swoole ADD ./database.php /swoole COPY 10-opcache.ini /etc/php/8.3/cli/conf.d/10-opcache.ini diff --git a/frameworks/PHP/swoole/swoole-async-postgres.dockerfile b/frameworks/PHP/swoole/swoole-async-postgres.dockerfile index 3bed20ce226..d431e125b3b 100644 --- a/frameworks/PHP/swoole/swoole-async-postgres.dockerfile +++ b/frameworks/PHP/swoole/swoole-async-postgres.dockerfile @@ -25,7 +25,6 @@ RUN apt update -yqq > /dev/null \ WORKDIR /swoole ADD ./swoole-server.php /swoole -ADD 10-opcache.ini /swoole ADD ./database.php /swoole COPY 10-opcache.ini /etc/php/8.3/cli/conf.d/10-opcache.ini diff --git a/frameworks/PHP/swoole/swoole-sync-mysql.dockerfile b/frameworks/PHP/swoole/swoole-sync-mysql.dockerfile index e8de37fd49b..c35d26cdc81 100644 --- a/frameworks/PHP/swoole/swoole-sync-mysql.dockerfile +++ b/frameworks/PHP/swoole/swoole-sync-mysql.dockerfile @@ -25,7 +25,6 @@ RUN apt update -yqq > /dev/null \ WORKDIR /swoole ADD ./swoole-server.php /swoole -ADD 10-opcache.ini /swoole ADD ./database.php /swoole COPY 10-opcache.ini /etc/php/8.3/cli/conf.d/10-opcache.ini diff --git a/frameworks/PHP/swoole/swoole-sync-postgres.dockerfile b/frameworks/PHP/swoole/swoole-sync-postgres.dockerfile index 670ea96ad4b..a2661c7c010 100644 --- a/frameworks/PHP/swoole/swoole-sync-postgres.dockerfile +++ b/frameworks/PHP/swoole/swoole-sync-postgres.dockerfile @@ -25,7 +25,6 @@ RUN apt update -yqq > /dev/null \ WORKDIR /swoole ADD ./swoole-server.php /swoole -ADD 10-opcache.ini /swoole ADD ./database.php /swoole COPY 10-opcache.ini /etc/php/8.3/cli/conf.d/10-opcache.ini From 93944012a393f1b434c0819fac34f47b225f3f7b Mon Sep 17 00:00:00 2001 From: Yury Zhuravlev Date: Tue, 22 Oct 2024 23:44:39 +0900 Subject: [PATCH 175/204] Update and fix sanic test (#9304) --- frameworks/Python/sanic/app.py | 56 ++++++++++--------- frameworks/Python/sanic/benchmark_config.json | 3 +- frameworks/Python/sanic/requirements.txt | 7 ++- frameworks/Python/sanic/sanic.dockerfile | 4 +- 4 files changed, 37 insertions(+), 33 deletions(-) diff --git a/frameworks/Python/sanic/app.py b/frameworks/Python/sanic/app.py index 47b374ce9a3..4070503205d 100644 --- a/frameworks/Python/sanic/app.py +++ b/frameworks/Python/sanic/app.py @@ -11,6 +11,8 @@ import sanic from sanic import response +from orjson import dumps + logger = getLogger(__name__) @@ -41,23 +43,26 @@ def get_num_queries(queries): return query_count -connection_pool = None sort_fortunes_key = itemgetter(1) template = load_fortunes_template() -app = sanic.Sanic(name=__name__) +app = sanic.Sanic(name=__name__, dumps=dumps) @app.listener('before_server_start') async def setup_database(app, loop): - global connection_pool - connection_pool = await asyncpg.create_pool( - user=os.getenv('PGUSER', 'benchmarkdbuser'), - password=os.getenv('PGPASS', 'benchmarkdbpass'), - database='hello_world', - host='tfb-database', - port=5432 - ) + app.ctx.pool = await asyncpg.create_pool( + user=os.getenv('PGUSER', 'benchmarkdbuser'), + password=os.getenv('PGPASS', 'benchmarkdbpass'), + database='hello_world', + host='tfb-database', + port=5432 + ) + + +@app.listener('after_server_stop') +async def close_database(app, loop): + app.ctx.pool.close() @app.get('/json') @@ -69,7 +74,7 @@ def json_view(request): async def single_database_query_view(request): row_id = randint(1, 10000) - async with connection_pool.acquire() as connection: + async with request.app.ctx.pool.acquire() as connection: number = await connection.fetchval(READ_ROW_SQL, row_id) return response.json( @@ -84,7 +89,7 @@ async def multiple_database_queries_view(request): row_ids = sample(range(1, 10000), num_queries) worlds = [] - async with connection_pool.acquire() as connection: + async with request.app.ctx.pool.acquire() as connection: statement = await connection.prepare(READ_ROW_SQL) for row_id in row_ids: number = await statement.fetchval(row_id) @@ -100,7 +105,7 @@ async def multiple_database_queries_view(request): @app.get('/fortunes') async def fortunes_view(request): - async with connection_pool.acquire() as connection: + async with request.app.ctx.pool.acquire() as connection: fortunes = await connection.fetch('SELECT * FROM Fortune') fortunes.append(ADDITIONAL_ROW) @@ -112,22 +117,21 @@ async def fortunes_view(request): @app.get('/updates') async def database_updates_view(request): - worlds = [] - updates = set() queries = request.args.get('queries', 1) + num_queries = get_num_queries(queries) + # To avoid deadlock + ids = sorted(sample(range(1, 10000 + 1), num_queries)) + numbers = sorted(sample(range(1, 10000), num_queries)) + updates = list(zip(ids, numbers)) - async with connection_pool.acquire() as connection: - statement = await connection.prepare(READ_ROW_SQL_TO_UPDATE) - - for row_id in sample(range(1, 10000), get_num_queries(queries)): - record = await statement.fetchrow(row_id) - world = dict( - id=record['id'], randomNumber=record['randomnumber'] - ) - world['randomNumber'] = randint(1, 10000) - worlds.append(world) - updates.add((world['id'], world['randomNumber'])) + worlds = [ + {"id": row_id, "randomNumber": number} for row_id, number in updates + ] + async with request.app.ctx.pool.acquire() as connection: + statement = await connection.prepare(READ_ROW_SQL) + for row_id, _ in updates: + await statement.fetchval(row_id) await connection.executemany(WRITE_ROW_SQL, updates) return response.json(worlds, headers=get_headers()) diff --git a/frameworks/Python/sanic/benchmark_config.json b/frameworks/Python/sanic/benchmark_config.json index b1bdd529d60..b3c6799b42b 100644 --- a/frameworks/Python/sanic/benchmark_config.json +++ b/frameworks/Python/sanic/benchmark_config.json @@ -23,8 +23,7 @@ "database_os": "Linux", "display_name": "Sanic", "notes": "", - "versus": "None", - "tags": ["broken"] + "versus": "None" } } ] diff --git a/frameworks/Python/sanic/requirements.txt b/frameworks/Python/sanic/requirements.txt index 5b4738e167d..ff8b4afd8a9 100644 --- a/frameworks/Python/sanic/requirements.txt +++ b/frameworks/Python/sanic/requirements.txt @@ -1,4 +1,5 @@ -asyncpg==0.25.0 +asyncpg==0.29.0 Jinja2==3.1.4 -sanic==22.6.1 -uvloop==0.16.0 +sanic==24.6.0 +uvloop==0.20.0 +orjson==3.10.7 \ No newline at end of file diff --git a/frameworks/Python/sanic/sanic.dockerfile b/frameworks/Python/sanic/sanic.dockerfile index 9619237ed21..d12ebcb391a 100644 --- a/frameworks/Python/sanic/sanic.dockerfile +++ b/frameworks/Python/sanic/sanic.dockerfile @@ -1,8 +1,8 @@ -FROM python:3.8 +FROM python:3.12 ADD ./requirements.txt /sanic/requirements.txt -RUN pip3 install cython==0.29.13 && \ +RUN pip3 install cython==3.0.11 && \ pip3 install -r /sanic/requirements.txt ADD ./ /sanic From d8c3011f5ada78572e05ea7f18cc5243c0754af6 Mon Sep 17 00:00:00 2001 From: lospejos Date: Tue, 22 Oct 2024 17:44:58 +0300 Subject: [PATCH 176/204] Bumped Go version to 1.23.1, dependencies versions for Go/Chi framework tests (#9320) * Bumped version for Java, Jooby, Maven and other libraries/dependencies * Bumped dependencies versions * Bumped dependencies versions * Bumped dependencies versions * Bumped dependencies versions * Fixed Resource_ issue * Bumped versions for Golang, Fiber and other dependencies * Bumped many deps versions, removed deprecated reuseBuffer() in Rocker * Bumped versions for Golang, Fiber and other dependencies * Updated Java version, Maven Docker image, Jooby, Netty versions * Bumped pgx version * Bumped Go version to 1.23.1, dependencies versions --- frameworks/Go/chi/chi-gojay-prefork.dockerfile | 2 +- frameworks/Go/chi/chi-gojay.dockerfile | 2 +- frameworks/Go/chi/chi-prefork.dockerfile | 2 +- frameworks/Go/chi/chi-scratch.dockerfile | 7 +++---- frameworks/Go/chi/chi-sjson-prefork.dockerfile | 2 +- frameworks/Go/chi/chi-sjson.dockerfile | 2 +- frameworks/Go/chi/chi.dockerfile | 2 +- frameworks/Go/chi/src/chi-gojay/go.mod | 8 +++++--- frameworks/Go/chi/src/chi-gojay/go.sum | 10 ++++++---- frameworks/Go/chi/src/chi-sjson/go.mod | 8 +++++--- frameworks/Go/chi/src/chi-sjson/go.sum | 10 ++++++---- frameworks/Go/chi/src/chi/go.mod | 11 +++++++---- frameworks/Go/chi/src/chi/go.sum | 10 ++++++---- frameworks/Go/fiber/fiber-prefork.dockerfile | 12 ++++++++---- frameworks/Go/fiber/fiber.dockerfile | 12 ++++++++---- 15 files changed, 60 insertions(+), 40 deletions(-) diff --git a/frameworks/Go/chi/chi-gojay-prefork.dockerfile b/frameworks/Go/chi/chi-gojay-prefork.dockerfile index 2403792062f..5c9eec667f7 100644 --- a/frameworks/Go/chi/chi-gojay-prefork.dockerfile +++ b/frameworks/Go/chi/chi-gojay-prefork.dockerfile @@ -1,4 +1,4 @@ -FROM docker.io/golang:1.19 +FROM docker.io/golang:1.23.1 ADD ./src/chi-gojay /chi WORKDIR /chi diff --git a/frameworks/Go/chi/chi-gojay.dockerfile b/frameworks/Go/chi/chi-gojay.dockerfile index 4f4e2ccf72d..c9a6de386d5 100644 --- a/frameworks/Go/chi/chi-gojay.dockerfile +++ b/frameworks/Go/chi/chi-gojay.dockerfile @@ -1,4 +1,4 @@ -FROM docker.io/golang:1.19 +FROM docker.io/golang:1.23.1 ADD ./src/chi-gojay /chi WORKDIR /chi diff --git a/frameworks/Go/chi/chi-prefork.dockerfile b/frameworks/Go/chi/chi-prefork.dockerfile index a516efa3726..fb363d7b06a 100644 --- a/frameworks/Go/chi/chi-prefork.dockerfile +++ b/frameworks/Go/chi/chi-prefork.dockerfile @@ -1,4 +1,4 @@ -FROM docker.io/golang:1.19 +FROM docker.io/golang:1.23.1 ADD ./src/chi /chi WORKDIR /chi diff --git a/frameworks/Go/chi/chi-scratch.dockerfile b/frameworks/Go/chi/chi-scratch.dockerfile index 63f9b7ac031..2361e658ca7 100644 --- a/frameworks/Go/chi/chi-scratch.dockerfile +++ b/frameworks/Go/chi/chi-scratch.dockerfile @@ -1,13 +1,12 @@ # build layer -FROM docker.io/golang:1.19-alpine as builder +FROM docker.io/golang:1.23.1-alpine as builder ADD ./src/chi /chi WORKDIR /chi RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 GOAMD64=v3 \ - go build -ldflags="-w -s" -o server - -RUN apk --no-cache add --update ca-certificates + go build -ldflags="-w -s" -o server && \ + apk --no-cache add --update ca-certificates # release layer FROM scratch diff --git a/frameworks/Go/chi/chi-sjson-prefork.dockerfile b/frameworks/Go/chi/chi-sjson-prefork.dockerfile index 1e6e7029c01..97071fe5e22 100644 --- a/frameworks/Go/chi/chi-sjson-prefork.dockerfile +++ b/frameworks/Go/chi/chi-sjson-prefork.dockerfile @@ -1,4 +1,4 @@ -FROM docker.io/golang:1.19 +FROM docker.io/golang:1.23.1 ADD ./src/chi-sjson /chi WORKDIR /chi diff --git a/frameworks/Go/chi/chi-sjson.dockerfile b/frameworks/Go/chi/chi-sjson.dockerfile index 6af99dc4011..99a2204147f 100644 --- a/frameworks/Go/chi/chi-sjson.dockerfile +++ b/frameworks/Go/chi/chi-sjson.dockerfile @@ -1,4 +1,4 @@ -FROM docker.io/golang:1.19 +FROM docker.io/golang:1.23.1 ADD ./src/chi-sjson /chi WORKDIR /chi diff --git a/frameworks/Go/chi/chi.dockerfile b/frameworks/Go/chi/chi.dockerfile index 205c2bdf7d5..6facc00990f 100644 --- a/frameworks/Go/chi/chi.dockerfile +++ b/frameworks/Go/chi/chi.dockerfile @@ -1,4 +1,4 @@ -FROM docker.io/golang:1.19 +FROM docker.io/golang:1.23.1 ADD ./src/chi /chi WORKDIR /chi diff --git a/frameworks/Go/chi/src/chi-gojay/go.mod b/frameworks/Go/chi/src/chi-gojay/go.mod index 8521c5e7b7f..f8c266996ec 100644 --- a/frameworks/Go/chi/src/chi-gojay/go.mod +++ b/frameworks/Go/chi/src/chi-gojay/go.mod @@ -1,8 +1,10 @@ module chi/server -go 1.19 +go 1.23.1 require ( - github.com/go-chi/chi/v5 v5.0.7 - github.com/go-sql-driver/mysql v1.6.0 + github.com/go-chi/chi/v5 v5.1.0 + github.com/go-sql-driver/mysql v1.8.1 ) + +require filippo.io/edwards25519 v1.1.0 // indirect diff --git a/frameworks/Go/chi/src/chi-gojay/go.sum b/frameworks/Go/chi/src/chi-gojay/go.sum index 68a8dd38f73..701d0184cbb 100644 --- a/frameworks/Go/chi/src/chi-gojay/go.sum +++ b/frameworks/Go/chi/src/chi-gojay/go.sum @@ -1,4 +1,6 @@ -github.com/go-chi/chi/v5 v5.0.7 h1:rDTPXLDHGATaeHvVlLcR4Qe0zftYethFucbjVQ1PxU8= -github.com/go-chi/chi/v5 v5.0.7/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= -github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE= -github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= +filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= +filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= +github.com/go-chi/chi/v5 v5.1.0 h1:acVI1TYaD+hhedDJ3r54HyA6sExp3HfXq7QWEEY/xMw= +github.com/go-chi/chi/v5 v5.1.0/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= +github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y= +github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg= diff --git a/frameworks/Go/chi/src/chi-sjson/go.mod b/frameworks/Go/chi/src/chi-sjson/go.mod index 8521c5e7b7f..f8c266996ec 100644 --- a/frameworks/Go/chi/src/chi-sjson/go.mod +++ b/frameworks/Go/chi/src/chi-sjson/go.mod @@ -1,8 +1,10 @@ module chi/server -go 1.19 +go 1.23.1 require ( - github.com/go-chi/chi/v5 v5.0.7 - github.com/go-sql-driver/mysql v1.6.0 + github.com/go-chi/chi/v5 v5.1.0 + github.com/go-sql-driver/mysql v1.8.1 ) + +require filippo.io/edwards25519 v1.1.0 // indirect diff --git a/frameworks/Go/chi/src/chi-sjson/go.sum b/frameworks/Go/chi/src/chi-sjson/go.sum index 68a8dd38f73..701d0184cbb 100644 --- a/frameworks/Go/chi/src/chi-sjson/go.sum +++ b/frameworks/Go/chi/src/chi-sjson/go.sum @@ -1,4 +1,6 @@ -github.com/go-chi/chi/v5 v5.0.7 h1:rDTPXLDHGATaeHvVlLcR4Qe0zftYethFucbjVQ1PxU8= -github.com/go-chi/chi/v5 v5.0.7/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= -github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE= -github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= +filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= +filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= +github.com/go-chi/chi/v5 v5.1.0 h1:acVI1TYaD+hhedDJ3r54HyA6sExp3HfXq7QWEEY/xMw= +github.com/go-chi/chi/v5 v5.1.0/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= +github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y= +github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg= diff --git a/frameworks/Go/chi/src/chi/go.mod b/frameworks/Go/chi/src/chi/go.mod index 829aae200bd..906b029b388 100644 --- a/frameworks/Go/chi/src/chi/go.mod +++ b/frameworks/Go/chi/src/chi/go.mod @@ -1,11 +1,14 @@ module chi/server -go 1.19 +go 1.23.1 require ( - github.com/go-chi/chi/v5 v5.0.7 - github.com/go-sql-driver/mysql v1.6.0 + github.com/go-chi/chi/v5 v5.1.0 + github.com/go-sql-driver/mysql v1.8.1 github.com/mailru/easyjson v0.7.7 ) -require github.com/josharian/intern v1.0.0 // indirect +require ( + filippo.io/edwards25519 v1.1.0 // indirect + github.com/josharian/intern v1.0.0 // indirect +) diff --git a/frameworks/Go/chi/src/chi/go.sum b/frameworks/Go/chi/src/chi/go.sum index f18160ebd73..b39d37edbe5 100644 --- a/frameworks/Go/chi/src/chi/go.sum +++ b/frameworks/Go/chi/src/chi/go.sum @@ -1,7 +1,9 @@ -github.com/go-chi/chi/v5 v5.0.7 h1:rDTPXLDHGATaeHvVlLcR4Qe0zftYethFucbjVQ1PxU8= -github.com/go-chi/chi/v5 v5.0.7/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= -github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE= -github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= +filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= +filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= +github.com/go-chi/chi/v5 v5.1.0 h1:acVI1TYaD+hhedDJ3r54HyA6sExp3HfXq7QWEEY/xMw= +github.com/go-chi/chi/v5 v5.1.0/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= +github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y= +github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= diff --git a/frameworks/Go/fiber/fiber-prefork.dockerfile b/frameworks/Go/fiber/fiber-prefork.dockerfile index c741baca1b8..43995ca7de7 100644 --- a/frameworks/Go/fiber/fiber-prefork.dockerfile +++ b/frameworks/Go/fiber/fiber-prefork.dockerfile @@ -1,14 +1,18 @@ -FROM docker.io/golang:1.23 +FROM golang:1.23-alpine as builder WORKDIR /fiber COPY ./src /fiber -RUN go mod download +RUN go mod download && \ + go generate -x ./templates && \ + GOAMD64=v3 go build -ldflags="-s -w" -o app . -RUN go generate -x ./templates +FROM alpine:latest -RUN GOAMD64=v3 go build -ldflags="-s -w" -o app . +WORKDIR /fiber + +COPY --from=builder /fiber/app . EXPOSE 8080 diff --git a/frameworks/Go/fiber/fiber.dockerfile b/frameworks/Go/fiber/fiber.dockerfile index 23c8ab72ea7..38f97b03d56 100644 --- a/frameworks/Go/fiber/fiber.dockerfile +++ b/frameworks/Go/fiber/fiber.dockerfile @@ -1,14 +1,18 @@ -FROM docker.io/golang:1.23 +FROM golang:1.23-alpine as builder WORKDIR /fiber COPY ./src /fiber -RUN go mod download +RUN go mod download && \ + go generate -x ./templates && \ + GOAMD64=v3 go build -ldflags="-s -w" -o app . -RUN go generate -x ./templates +FROM alpine:latest -RUN GOAMD64=v3 go build -ldflags="-s -w" -o app . +WORKDIR /fiber + +COPY --from=builder /fiber/app . EXPOSE 8080 From 55c143645c5b943aff7736d7db305ac74c0d9717 Mon Sep 17 00:00:00 2001 From: Aaron Tavistock Date: Tue, 22 Oct 2024 07:45:42 -0700 Subject: [PATCH 177/204] [Elixir/phoenix] Implementing suggestions from @josevalim (#9302) * Implementing suggestions from @josevalim * We don't need to worry about 'accepts' plug in this case * Prematurely removed accepts plug (still needed for 'fortunes' test) * Avoid checking a list we don't need to * Using explicit content-type for plain-text * Updating ecto to use pool count (also tested different count/size groupings) * db pools set for the target machine --- frameworks/Elixir/phoenix/config/prod.exs | 17 +--- .../Elixir/phoenix/lib/hello/world_cache.ex | 2 +- frameworks/Elixir/phoenix/lib/hello_web.ex | 4 +- .../hello_web/controllers/page_controller.ex | 97 ++++++++++--------- .../Elixir/phoenix/lib/hello_web/endpoint.ex | 1 - .../Elixir/phoenix/lib/hello_web/router.ex | 6 -- frameworks/Elixir/phoenix/mix.lock | 4 +- 7 files changed, 56 insertions(+), 75 deletions(-) diff --git a/frameworks/Elixir/phoenix/config/prod.exs b/frameworks/Elixir/phoenix/config/prod.exs index 9ad458a09be..c920950ee04 100755 --- a/frameworks/Elixir/phoenix/config/prod.exs +++ b/frameworks/Elixir/phoenix/config/prod.exs @@ -21,7 +21,8 @@ config :hello, Hello.Repo, password: "benchmarkdbpass", database: "hello_world", hostname: "tfb-database", - pool_size: 50, + pool_count: 56, + pool_size: 15, queue_target: 5000, log: false @@ -33,17 +34,3 @@ config :logger, ], level: :error, backends: [] - -# ## SSL Support -# -# To get SSL working, you will need to add the `https` key -# to the previous section: -# -# config:hello, Hello.Endpoint, -# ... -# https: [port: 443, -# keyfile: System.get_env("SOME_APP_SSL_KEY_PATH"), -# certfile: System.get_env("SOME_APP_SSL_CERT_PATH")] -# -# Where those two env variables point to a file on -# disk for the key and cert. diff --git a/frameworks/Elixir/phoenix/lib/hello/world_cache.ex b/frameworks/Elixir/phoenix/lib/hello/world_cache.ex index b4943e14a35..e6cde7ab58e 100644 --- a/frameworks/Elixir/phoenix/lib/hello/world_cache.ex +++ b/frameworks/Elixir/phoenix/lib/hello/world_cache.ex @@ -23,9 +23,9 @@ defmodule Hello.WorldCache do world = Repo.get(World, id) :ok = __MODULE__.put(id, world) world + world -> world end end - end diff --git a/frameworks/Elixir/phoenix/lib/hello_web.ex b/frameworks/Elixir/phoenix/lib/hello_web.ex index 1193aab23a5..1114ed22e51 100644 --- a/frameworks/Elixir/phoenix/lib/hello_web.ex +++ b/frameworks/Elixir/phoenix/lib/hello_web.ex @@ -95,8 +95,8 @@ defmodule HelloWeb do end @doc """ - When used, dispatch to the appropriate controller/view/etc. - """ + When used, dispatch to the appropriate controller/view/etc. + """ defmacro __using__(which) when is_atom(which) do apply(__MODULE__, which, []) end diff --git a/frameworks/Elixir/phoenix/lib/hello_web/controllers/page_controller.ex b/frameworks/Elixir/phoenix/lib/hello_web/controllers/page_controller.ex index 7cb7d1fbe2b..59f2f5c2f35 100644 --- a/frameworks/Elixir/phoenix/lib/hello_web/controllers/page_controller.ex +++ b/frameworks/Elixir/phoenix/lib/hello_web/controllers/page_controller.ex @@ -8,6 +8,8 @@ defmodule HelloWeb.PageController do @random_max 10_000 + plug :accepts, ~w(html json) when action == :fortunes + def index(conn, _params) do json(conn, %{"TE Benchmarks\n" => "Started"}) end @@ -24,17 +26,11 @@ defmodule HelloWeb.PageController do end def queries(conn, params) do - {:ok, worlds} = - Repo.transaction(fn -> - :rand.seed(:exsp) - - worlds = - Stream.repeatedly(&random_id/0) - |> Stream.uniq() - |> Stream.map(&Repo.get(World, &1)) - |> Enum.take(size(params["queries"])) - - worlds + worlds = + Repo.checkout(fn -> + params["queries"] + |> random_ids_sample() + |> Enum.map(&Repo.get(World, &1)) end) json(conn, worlds) @@ -48,54 +44,53 @@ defmodule HelloWeb.PageController do fortunes = [additional_fortune | Repo.all(Fortune)] - |> Enum.sort_by(& &1.message) + |> Enum.sort(fn a, b -> a.message < b.message end) render(conn, :fortunes, fortunes: fortunes) end def updates(conn, params) do - {:ok, worlds} = - Repo.transaction(fn -> - :rand.seed(:exsp) - - worlds = - Stream.repeatedly(&random_id/0) - |> Stream.uniq() - |> Stream.map(&Repo.get(World, &1)) - |> Stream.map(fn world -> %{id: world.id, randomnumber: :rand.uniform(@random_max)} end) - |> Enum.take(size(params["queries"])) - # If this is not sorted it sometimes generates - # FAIL for http://tfb-server:8080/updates/20 - # Only 20470 executed queries in the database out of roughly 20480 expected. - |> Enum.sort_by(& &1.id) - - Repo.insert_all( - World, - worlds, - on_conflict: {:replace_all_except, [:id]}, - conflict_target: [:id], - returning: false - ) - - worlds + world_updates = + Repo.checkout(fn -> + params["queries"] + |> random_ids_sample() + |> Enum.sort() + # + # If this is not sorted it will intermittently generate: + # + # FAIL for http://tfb-server:8080/updates/20 + # Only 20470 executed queries in the database out of roughly 20480 expected. + # + |> Enum.map(fn id -> + world = Repo.get(World, id) + %{id: world.id, randomnumber: :rand.uniform(@random_max)} + end) end) - json(conn, worlds) + Repo.insert_all( + World, + world_updates, + on_conflict: {:replace_all_except, [:id]}, + conflict_target: [:id], + returning: false + ) + + json(conn, world_updates) end - def plaintext(conn, _params) do - text(conn, "Hello, World!") + def plaintext(conn, _params) do + conn + |> put_resp_header("content-type", "text/plain") + |> send_resp(200, "Hello, World!") end def cached(conn, params) do - :rand.seed(:exsp) WorldCache.seed() worlds = - Stream.repeatedly(&random_id/0) - |> Stream.uniq() - |> Stream.map(&WorldCache.fetch(&1)) - |> Enum.take(size(params["count"])) + params["count"] + |> random_ids_sample() + |> Enum.map(&WorldCache.fetch(&1)) json(conn, worlds) end @@ -104,11 +99,17 @@ defmodule HelloWeb.PageController do :rand.uniform(@random_max) end - defp size(nil), do: 1 - defp size(""), do: 1 + defp random_ids_sample(count) do + # Use the fastest rand algorithm + :rand.seed(:exsp) + + Stream.repeatedly(&random_id/0) + |> Stream.uniq() + |> Enum.take(size(count)) + end - defp size(queries) when is_bitstring(queries) do - case Integer.parse(queries) do + defp size(param_count) when is_bitstring(param_count) do + case Integer.parse(param_count) do {count, _} -> max(1, min(500, count)) _ -> 1 end diff --git a/frameworks/Elixir/phoenix/lib/hello_web/endpoint.ex b/frameworks/Elixir/phoenix/lib/hello_web/endpoint.ex index f709d00a2e8..a764bbf653e 100644 --- a/frameworks/Elixir/phoenix/lib/hello_web/endpoint.ex +++ b/frameworks/Elixir/phoenix/lib/hello_web/endpoint.ex @@ -20,4 +20,3 @@ defmodule HelloWeb.Endpoint do plug HelloWeb.HeadersPlug plug HelloWeb.Router end - diff --git a/frameworks/Elixir/phoenix/lib/hello_web/router.ex b/frameworks/Elixir/phoenix/lib/hello_web/router.ex index 1634f3403fd..7e3caed3b8f 100755 --- a/frameworks/Elixir/phoenix/lib/hello_web/router.ex +++ b/frameworks/Elixir/phoenix/lib/hello_web/router.ex @@ -1,13 +1,7 @@ defmodule HelloWeb.Router do use HelloWeb, :router - pipeline :browser do - plug :accepts, ~w(html json) - end - scope "/", HelloWeb do - pipe_through [:browser] - get "/json", PageController, :_json get "/db", PageController, :db get "/queries", PageController, :queries diff --git a/frameworks/Elixir/phoenix/mix.lock b/frameworks/Elixir/phoenix/mix.lock index 4c59758f12a..0c47cab2458 100644 --- a/frameworks/Elixir/phoenix/mix.lock +++ b/frameworks/Elixir/phoenix/mix.lock @@ -6,8 +6,8 @@ "cowlib": {:hex, :cowlib, "2.13.0", "db8f7505d8332d98ef50a3ef34b34c1afddec7506e4ee4dd4a3a266285d282ca", [:make, :rebar3], [], "hexpm", "e1e1284dc3fc030a64b1ad0d8382ae7e99da46c3246b815318a4b848873800a4"}, "db_connection": {:hex, :db_connection, "2.7.0", "b99faa9291bb09892c7da373bb82cba59aefa9b36300f6145c5f201c7adf48ec", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "dcf08f31b2701f857dfc787fbad78223d61a32204f217f15e881dd93e4bdd3ff"}, "decimal": {:hex, :decimal, "2.1.1", "5611dca5d4b2c3dd497dec8f68751f1f1a54755e8ed2a966c2633cf885973ad6", [:mix], [], "hexpm", "53cfe5f497ed0e7771ae1a475575603d77425099ba5faef9394932b35020ffcc"}, - "ecto": {:hex, :ecto, "3.11.2", "e1d26be989db350a633667c5cda9c3d115ae779b66da567c68c80cfb26a8c9ee", [:mix], [{:decimal, "~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "3c38bca2c6f8d8023f2145326cc8a80100c3ffe4dcbd9842ff867f7fc6156c65"}, - "ecto_sql": {:hex, :ecto_sql, "3.11.3", "4eb7348ff8101fbc4e6bbc5a4404a24fecbe73a3372d16569526b0cf34ebc195", [:mix], [{:db_connection, "~> 2.4.1 or ~> 2.5", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.11.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:myxql, "~> 0.6", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.16 or ~> 1.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:tds, "~> 2.1.1 or ~> 2.2", [hex: :tds, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "e5f36e3d736b99c7fee3e631333b8394ade4bafe9d96d35669fca2d81c2be928"}, + "ecto": {:hex, :ecto, "3.12.4", "267c94d9f2969e6acc4dd5e3e3af5b05cdae89a4d549925f3008b2b7eb0b93c3", [:mix], [{:decimal, "~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "ef04e4101688a67d061e1b10d7bc1fbf00d1d13c17eef08b71d070ff9188f747"}, + "ecto_sql": {:hex, :ecto_sql, "3.12.1", "c0d0d60e85d9ff4631f12bafa454bc392ce8b9ec83531a412c12a0d415a3a4d0", [:mix], [{:db_connection, "~> 2.4.1 or ~> 2.5", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.12", [hex: :ecto, repo: "hexpm", optional: false]}, {:myxql, "~> 0.7", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.19 or ~> 1.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:tds, "~> 2.1.1 or ~> 2.2", [hex: :tds, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "aff5b958a899762c5f09028c847569f7dfb9cc9d63bdb8133bff8a5546de6bf5"}, "expo": {:hex, :expo, "1.0.0", "647639267e088717232f4d4451526e7a9de31a3402af7fcbda09b27e9a10395a", [:mix], [], "hexpm", "18d2093d344d97678e8a331ca0391e85d29816f9664a25653fd7e6166827827c"}, "gettext": {:hex, :gettext, "0.25.0", "98a95a862a94e2d55d24520dd79256a15c87ea75b49673a2e2f206e6ebc42e5d", [:mix], [{:expo, "~> 0.5.1 or ~> 1.0", [hex: :expo, repo: "hexpm", optional: false]}], "hexpm", "38e5d754e66af37980a94fb93bb20dcde1d2361f664b0a19f01e87296634051f"}, "hpax": {:hex, :hpax, "1.0.0", "28dcf54509fe2152a3d040e4e3df5b265dcb6cb532029ecbacf4ce52caea3fd2", [:mix], [], "hexpm", "7f1314731d711e2ca5fdc7fd361296593fc2542570b3105595bb0bc6d0fad601"}, From 7c7cceea1ab3bab63c77a4de9005a47cc69c876c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Tue, 22 Oct 2024 16:46:30 +0200 Subject: [PATCH 178/204] [elixir/plug] Clean up boilerplate when encoding to Jason (#9301) --- .../framework_benchmarks/handlers/cached-world.ex | 4 ++-- .../plug/lib/framework_benchmarks/handlers/db.ex | 6 ++---- .../plug/lib/framework_benchmarks/handlers/json.ex | 2 +- .../lib/framework_benchmarks/handlers/query.ex | 14 +++----------- .../lib/framework_benchmarks/handlers/update.ex | 14 +++----------- .../plug/lib/framework_benchmarks/models/world.ex | 1 + 6 files changed, 12 insertions(+), 29 deletions(-) diff --git a/frameworks/Elixir/plug/lib/framework_benchmarks/handlers/cached-world.ex b/frameworks/Elixir/plug/lib/framework_benchmarks/handlers/cached-world.ex index c80b71053e7..60b441557c5 100644 --- a/frameworks/Elixir/plug/lib/framework_benchmarks/handlers/cached-world.ex +++ b/frameworks/Elixir/plug/lib/framework_benchmarks/handlers/cached-world.ex @@ -11,10 +11,10 @@ defmodule FrameworkBenchmarks.Handlers.CachedWorld do :rand.uniform(10_000) end) - {:ok, json} = + json = ids |> Enum.map(&FrameworkBenchmarks.CachedWorld.get/1) - |> Jason.encode() + |> Jason.encode_to_iodata!() conn |> Plug.Conn.put_resp_content_type("application/json") diff --git a/frameworks/Elixir/plug/lib/framework_benchmarks/handlers/db.ex b/frameworks/Elixir/plug/lib/framework_benchmarks/handlers/db.ex index b1abba5dd8b..101b7e5f8fd 100644 --- a/frameworks/Elixir/plug/lib/framework_benchmarks/handlers/db.ex +++ b/frameworks/Elixir/plug/lib/framework_benchmarks/handlers/db.ex @@ -5,11 +5,9 @@ defmodule FrameworkBenchmarks.Handlers.DB do def handle(conn) do id = :rand.uniform(10_000) - {:ok, json} = + json = FrameworkBenchmarks.Repo.get(FrameworkBenchmarks.Models.World, id) - |> Map.from_struct() - |> Map.drop([:__meta__]) - |> Jason.encode() + |> Jason.encode_to_iodata!() conn |> Plug.Conn.put_resp_content_type("application/json") diff --git a/frameworks/Elixir/plug/lib/framework_benchmarks/handlers/json.ex b/frameworks/Elixir/plug/lib/framework_benchmarks/handlers/json.ex index c013110a6de..3a7ada06cdb 100644 --- a/frameworks/Elixir/plug/lib/framework_benchmarks/handlers/json.ex +++ b/frameworks/Elixir/plug/lib/framework_benchmarks/handlers/json.ex @@ -3,7 +3,7 @@ defmodule FrameworkBenchmarks.Handlers.JSON do This is the handle for the /json route """ def handle(conn) do - {:ok, json} = Jason.encode(%{message: "Hello, World!"}) + json = Jason.encode_to_iodata!(%{message: "Hello, World!"}) conn |> Plug.Conn.put_resp_content_type("application/json") diff --git a/frameworks/Elixir/plug/lib/framework_benchmarks/handlers/query.ex b/frameworks/Elixir/plug/lib/framework_benchmarks/handlers/query.ex index b4e83026a82..6ad2af9061a 100644 --- a/frameworks/Elixir/plug/lib/framework_benchmarks/handlers/query.ex +++ b/frameworks/Elixir/plug/lib/framework_benchmarks/handlers/query.ex @@ -5,7 +5,7 @@ defmodule FrameworkBenchmarks.Handlers.Query do def handle(conn) do number_of_queries = FrameworkBenchmarks.Handlers.Helpers.parse_queries(conn, "queries") - records = + json = 1..number_of_queries |> Enum.map(fn _ -> :rand.uniform(10_000) @@ -15,16 +15,8 @@ defmodule FrameworkBenchmarks.Handlers.Query do FrameworkBenchmarks.Repo.get(FrameworkBenchmarks.Models.World, &1) end) ) - |> Enum.map(&Task.await(&1)) - - {:ok, json} = - records - |> Enum.map(fn record -> - record - |> Map.from_struct() - |> Map.drop([:__meta__]) - end) - |> Jason.encode() + |> Enum.map(&Task.await(&1, :infinity)) + |> Jason.encode_to_iodata!() conn |> Plug.Conn.put_resp_content_type("application/json") diff --git a/frameworks/Elixir/plug/lib/framework_benchmarks/handlers/update.ex b/frameworks/Elixir/plug/lib/framework_benchmarks/handlers/update.ex index d06744adfde..0b5ad54c4b8 100644 --- a/frameworks/Elixir/plug/lib/framework_benchmarks/handlers/update.ex +++ b/frameworks/Elixir/plug/lib/framework_benchmarks/handlers/update.ex @@ -22,7 +22,7 @@ defmodule FrameworkBenchmarks.Handlers.Update do :rand.uniform(10_000) end) - records = + json = ids |> Enum.map( &Task.async(fn -> @@ -38,16 +38,8 @@ defmodule FrameworkBenchmarks.Handlers.Update do |> FrameworkBenchmarks.Repo.update!() end) ) - |> Enum.map(&Task.await(&1)) - - {:ok, json} = - records - |> Enum.map(fn record -> - record - |> Map.from_struct() - |> Map.drop([:__meta__]) - end) - |> Jason.encode() + |> Enum.map(&Task.await(&1, :infinity)) + |> Jason.encode_to_iodata!() conn |> Plug.Conn.put_resp_content_type("application/json") diff --git a/frameworks/Elixir/plug/lib/framework_benchmarks/models/world.ex b/frameworks/Elixir/plug/lib/framework_benchmarks/models/world.ex index 549d8415a9e..d3db33611c1 100644 --- a/frameworks/Elixir/plug/lib/framework_benchmarks/models/world.ex +++ b/frameworks/Elixir/plug/lib/framework_benchmarks/models/world.ex @@ -1,6 +1,7 @@ defmodule FrameworkBenchmarks.Models.World do use Ecto.Schema + @derive {Jason.Encoder, only: [:id, :randomnumber]} schema "world" do field(:randomnumber, :integer) end From 540de89f044864114b255d34d78bfd17eec17be5 Mon Sep 17 00:00:00 2001 From: Dragos Varovici Date: Tue, 22 Oct 2024 08:46:41 -0600 Subject: [PATCH 179/204] Added Zig Httpz framework (#9298) * Added Zig httpz framework * Zig httpz fortunes --- frameworks/Zig/httpz/.gitignore | 2 + frameworks/Zig/httpz/README.md | 25 +++ frameworks/Zig/httpz/benchmark_config.json | 26 +++ frameworks/Zig/httpz/build.zig | 78 +++++++++ frameworks/Zig/httpz/build.zig.zon | 19 ++ frameworks/Zig/httpz/httpz.dockerfile | 23 +++ frameworks/Zig/httpz/run.sh | 3 + frameworks/Zig/httpz/src/endpoints.zig | 192 +++++++++++++++++++++ frameworks/Zig/httpz/src/main.zig | 71 ++++++++ frameworks/Zig/httpz/src/pool.zig | 87 ++++++++++ 10 files changed, 526 insertions(+) create mode 100644 frameworks/Zig/httpz/.gitignore create mode 100644 frameworks/Zig/httpz/README.md create mode 100644 frameworks/Zig/httpz/benchmark_config.json create mode 100644 frameworks/Zig/httpz/build.zig create mode 100644 frameworks/Zig/httpz/build.zig.zon create mode 100644 frameworks/Zig/httpz/httpz.dockerfile create mode 100644 frameworks/Zig/httpz/run.sh create mode 100644 frameworks/Zig/httpz/src/endpoints.zig create mode 100644 frameworks/Zig/httpz/src/main.zig create mode 100644 frameworks/Zig/httpz/src/pool.zig diff --git a/frameworks/Zig/httpz/.gitignore b/frameworks/Zig/httpz/.gitignore new file mode 100644 index 00000000000..170dc0f1403 --- /dev/null +++ b/frameworks/Zig/httpz/.gitignore @@ -0,0 +1,2 @@ +zig-cache/**/*', +zig-out: 'zig-out/**/*', diff --git a/frameworks/Zig/httpz/README.md b/frameworks/Zig/httpz/README.md new file mode 100644 index 00000000000..e83169efe17 --- /dev/null +++ b/frameworks/Zig/httpz/README.md @@ -0,0 +1,25 @@ + +# [Httpz](https://github.com/karlseguin/http.zig) - An HTTP/1.1 server for Zig + +## Description + +Native Zig framework and zig http replacement + +## Test URLs + +### Test 1: JSON Encoding + + http://localhost:3000/json + +### Test 2: Plaintext + + http://localhost:3000/plaintext + +### Test 2: Single Row Query + + http://localhost:3000/db + +### Test 4: Fortunes (Template rendering) + + http://localhost:3000/fortunes + diff --git a/frameworks/Zig/httpz/benchmark_config.json b/frameworks/Zig/httpz/benchmark_config.json new file mode 100644 index 00000000000..e36c9c17a1c --- /dev/null +++ b/frameworks/Zig/httpz/benchmark_config.json @@ -0,0 +1,26 @@ +{ + "framework": "httpz", + "tests": [{ + "default": { + "json_url": "/json", + "plaintext_url": "/plaintext", + "db_url": "/db", + "fortune_url": "/fortunes", + "port": 3000, + "approach": "Realistic", + "classification": "Fullstack", + "database": "Postgres", + "framework": "httpz", + "language": "Zig", + "flavor": "None", + "orm": "raw", + "platform": "None", + "webserver": "None", + "os": "Linux", + "database_os": "Linux", + "display_name": "Httpz (Zig)", + "notes": "", + "versus": "" + } + }] +} diff --git a/frameworks/Zig/httpz/build.zig b/frameworks/Zig/httpz/build.zig new file mode 100644 index 00000000000..5978de7c6aa --- /dev/null +++ b/frameworks/Zig/httpz/build.zig @@ -0,0 +1,78 @@ +const std = @import("std"); +const ModuleMap = std.StringArrayHashMap(*std.Build.Module); +var gpa = std.heap.GeneralPurposeAllocator(.{}){}; +const allocator = gpa.allocator(); + +// Although this function looks imperative, note that its job is to +// declaratively construct a build graph that will be executed by an external +// runner. +pub fn build(b: *std.Build) !void { + // Standard target options allows the person running `zig build` to choose + // what target to build for. Here we do not override the defaults, which + // means any target is allowed, and the default is native. Other options + // for restricting supported target set are available. + const target = b.standardTargetOptions(.{}); + + // Standard optimization options allow the person running `zig build` to select + // between Debug, ReleaseSafe, ReleaseFast, and ReleaseSmall. Here we do nots + // set a preferred release mode, allowing the user to decide how to optimize. + const optimize = b.standardOptimizeOption(.{}); + + const dep_opts = .{ .target = target, .optimize = optimize }; + + const exe = b.addExecutable(.{ + .name = "httpz", + // In this case the main source file is merely a path, however, in more + // complicated build scripts, this could be a generated file. + .root_source_file = b.path("src/main.zig"), + .target = target, + .optimize = optimize, + }); + + var modules = ModuleMap.init(allocator); + defer modules.deinit(); + + const httpz_module = b.dependency("httpz", dep_opts).module("httpz"); + const pg_module = b.dependency("pg", dep_opts).module("pg"); + const datetimez_module = b.dependency("datetimez", dep_opts).module("zig-datetime"); + const mustache_module = b.dependency("mustache", dep_opts).module("mustache"); + + try modules.put("httpz", httpz_module); + try modules.put("pg", pg_module); + try modules.put("datetimez", datetimez_module); + try modules.put("mustache", mustache_module); + + // // Expose this as a module that others can import + exe.root_module.addImport("httpz", httpz_module); + exe.root_module.addImport("pg", pg_module); + exe.root_module.addImport("datetimez", datetimez_module); + exe.root_module.addImport("mustache", mustache_module); + + // This declares intent for the executable to be installed into the + // standard location when the user invokes the "install" step (the default + // step when running `zig build`). + b.installArtifact(exe); + + // This *creates* a Run step in the build graph, to be executed when another + // step is evaluated that depends on it. The next line below will establish + // such a dependency. + const run_cmd = b.addRunArtifact(exe); + + // By making the run step depend on the install step, it will be run from the + // installation directory rather than directly from within the cache directory. + // This is not necessary, however, if the application depends on other installed + // files, this ensures they will be present and in the expected location. + run_cmd.step.dependOn(b.getInstallStep()); + + // This allows the user to pass arguments to the application in the build + // command itself, like this: `zig build run -- arg1 arg2 etc` + if (b.args) |args| { + run_cmd.addArgs(args); + } + + // This creates a build step. It will be visible in the `zig build --help` menu, + // and can be selected like this: `zig build run` + // This will evaluate the `run` step rather than the default, which is "install". + const run_step = b.step("run", "Run the app"); + run_step.dependOn(&run_cmd.step); +} diff --git a/frameworks/Zig/httpz/build.zig.zon b/frameworks/Zig/httpz/build.zig.zon new file mode 100644 index 00000000000..58b494c2fe3 --- /dev/null +++ b/frameworks/Zig/httpz/build.zig.zon @@ -0,0 +1,19 @@ +.{ .name = "Zap testing", .version = "0.1.1", .paths = .{ + "build.zig", + "build.zig.zon", + "src", +}, .dependencies = .{ + .pg = .{ .url = "https://github.com/karlseguin/pg.zig/archive/239a4468163a49d8c0d03285632eabe96003e9e2.tar.gz", .hash = "1220a1d7e51e2fa45e547c76a9e099c09d06e14b0b9bfc6baa89367f56f1ded399a0" }, + .httpz = .{ + .url = "git+https://github.com/karlseguin/http.zig?ref=zig-0.13#7d2ddae87af9b110783085c0ea6b03985faa4584", + .hash = "12208c1f2c5f730c4c03aabeb0632ade7e21914af03e6510311b449458198d0835d6", + }, + .datetimez = .{ + .url = "git+https://github.com/frmdstryr/zig-datetime#70aebf28fb3e137cd84123a9349d157a74708721", + .hash = "122077215ce36e125a490e59ec1748ffd4f6ba00d4d14f7308978e5360711d72d77f", + }, + .mustache = .{ + .url = "git+https://github.com/batiati/mustache-zig#ae5ecc1522da983dc39bb0d8b27f5d1b1d7956e3", + .hash = "1220ac9e3316ce71ad9cd66c7f215462bf5c187828b50bb3d386549bf6af004e3bb0", + }, +} } diff --git a/frameworks/Zig/httpz/httpz.dockerfile b/frameworks/Zig/httpz/httpz.dockerfile new file mode 100644 index 00000000000..5257b77ea18 --- /dev/null +++ b/frameworks/Zig/httpz/httpz.dockerfile @@ -0,0 +1,23 @@ +FROM fedora:40 + +WORKDIR /httpz + +ENV PG_USER=benchmarkdbuser +ENV PG_PASS=benchmarkdbpass +ENV PG_DB=hello_world +ENV PG_HOST=tfb-database +ENV PG_PORT=5432 + +COPY src src +COPY build.zig.zon build.zig.zon +COPY build.zig build.zig +COPY run.sh run.sh + +RUN dnf install -y zig +RUN zig version +RUN zig build -Doptimize=ReleaseFast +RUN cp /httpz/zig-out/bin/httpz /usr/local/bin + +EXPOSE 3000 + +CMD ["sh", "run.sh"] \ No newline at end of file diff --git a/frameworks/Zig/httpz/run.sh b/frameworks/Zig/httpz/run.sh new file mode 100644 index 00000000000..582c2ad0228 --- /dev/null +++ b/frameworks/Zig/httpz/run.sh @@ -0,0 +1,3 @@ +echo "Waiting for Httpz framework to start..." + +httpz \ No newline at end of file diff --git a/frameworks/Zig/httpz/src/endpoints.zig b/frameworks/Zig/httpz/src/endpoints.zig new file mode 100644 index 00000000000..0ee22b274de --- /dev/null +++ b/frameworks/Zig/httpz/src/endpoints.zig @@ -0,0 +1,192 @@ +const std = @import("std"); +const httpz = @import("httpz"); +const pg = @import("pg"); +const datetimez = @import("datetimez"); +const mustache = @import("mustache"); + +const Allocator = std.mem.Allocator; +const Thread = std.Thread; +const Mutex = Thread.Mutex; +const template = "Fortunes{{#fortunes}}{{/fortunes}}
    idmessage
    {{id}}{{message}}
    "; + +pub const Global = struct { + pool: *pg.Pool, + prng: *std.rand.DefaultPrng, + allocator: Allocator, + mutex: std.Thread.Mutex = .{}, +}; + +const Message = struct { + message: []const u8, +}; + +const World = struct { + id: i32, + randomNumber: i32, +}; + +const Fortune = struct { + id: i32, + message: []const u8, +}; + +pub fn plaintext(global: *Global, _: *httpz.Request, res: *httpz.Response) !void { + try setHeaders(global.allocator, res); + + res.content_type = .TEXT; + res.body = "Hello, World!"; +} + +pub fn json(global: *Global, _: *httpz.Request, res: *httpz.Response) !void { + try setHeaders(global.allocator, res); + + const message = Message{ .message = "Hello, World!" }; + + try res.json(message, .{}); +} + +pub fn db(global: *Global, _: *httpz.Request, res: *httpz.Response) !void { + try setHeaders(global.allocator, res); + + global.mutex.lock(); + const random_number = 1 + (global.prng.random().uintAtMost(u32, 9999)); + global.mutex.unlock(); + + const world = getWorld(global.pool, random_number) catch |err| { + std.debug.print("Error querying database: {}\n", .{err}); + return; + }; + + try res.json(world, .{}); +} + +pub fn fortune(global: *Global, _: *httpz.Request, res: *httpz.Response) !void { + try setHeaders(global.allocator, res); + + const fortunes_html = try getFortunesHtml(global.allocator, global.pool); + + res.header("content-type", "text/html; charset=utf-8"); + res.body = fortunes_html; +} + +fn getWorld(pool: *pg.Pool, random_number: u32) !World{ + var conn = try pool.acquire(); + defer conn.release(); + + const row_result = try conn.row("SELECT id, randomNumber FROM World WHERE id = $1", .{random_number}); + + var row = row_result.?; + defer row.deinit() catch {}; + + return World{ .id = row.get(i32, 0), .randomNumber = row.get(i32, 1) }; +} + +fn setHeaders(allocator: Allocator, res: *httpz.Response) !void { + res.header("Server", "Httpz"); + + const now = datetimez.datetime.Date.now(); + const time = datetimez.datetime.Time.now(); + + // Wed, 17 Apr 2013 12:00:00 GMT + // Return date in ISO format YYYY-MM-DD + const TB_DATE_FMT = "{s:0>3}, {d:0>2} {s:0>3} {d:0>4} {d:0>2}:{d:0>2}:{d:0>2} GMT"; + const now_str = try std.fmt.allocPrint(allocator, TB_DATE_FMT, .{ now.weekdayName()[0..3], now.day, now.monthName()[0..3], now.year, time.hour, time.minute, time.second }); + + //defer allocator.free(now_str); + + res.header("Date", now_str); +} + +fn getFortunesHtml(allocator: Allocator, pool: *pg.Pool) ![]const u8 { + const fortunes = try getFortunes(allocator, pool); + + const raw = try mustache.allocRenderText(allocator, template,.{ .fortunes = fortunes }); + + // std.debug.print("mustache output {s}\n", .{raw}); + + const html = try deescapeHtml(allocator, raw); + + // std.debug.print("html output {s}\n", .{html}); + + return html; +} + +fn getFortunes(allocator: Allocator, pool: *pg.Pool) ![]const Fortune { + var conn = try pool.acquire(); + defer conn.release(); + + var rows = try conn.query("SELECT id, message FROM Fortune", .{}); + defer rows.deinit(); + + var fortunes = std.ArrayList(Fortune).init(allocator); + defer fortunes.deinit(); + + while (try rows.next()) |row| { + const current_fortune = Fortune{ .id = row.get(i32, 0), .message = row.get([]const u8, 1) }; + try fortunes.append(current_fortune); + } + + const zero_fortune = Fortune{ .id = 0, .message = "Additional fortune added at request time." }; + try fortunes.append(zero_fortune); + + const fortunes_slice = try fortunes.toOwnedSlice(); + std.mem.sort(Fortune, fortunes_slice, {}, cmpFortuneByMessage); + + return fortunes_slice; +} + +fn cmpFortuneByMessage(_: void, a: Fortune, b: Fortune) bool { + return std.mem.order(u8, a.message, b.message).compare(std.math.CompareOperator.lt); +} + +fn deescapeHtml(allocator: Allocator, input: []const u8) ![]const u8 { + var output = std.ArrayList(u8).init(allocator); + defer output.deinit(); + + var i: usize = 0; + while (i < input.len) { + if (std.mem.startsWith(u8, input[i..], " ")) { + try output.append(' '); + i += 5; + } else if (std.mem.startsWith(u8, input[i..], """)) { + try output.append('"'); + i += 5; + } else if (std.mem.startsWith(u8, input[i..], "&")) { + try output.append('&'); + i += 5; + } else if (std.mem.startsWith(u8, input[i..], "'")) { + try output.append('\''); + i += 5; + } else if (std.mem.startsWith(u8, input[i..], "(")) { + try output.append('('); + i += 5; + } else if (std.mem.startsWith(u8, input[i..], ")")) { + try output.append(')'); + i += 5; + } else if (std.mem.startsWith(u8, input[i..], "+")) { + try output.append('+'); + i += 5; + } else if (std.mem.startsWith(u8, input[i..], ",")) { + try output.append(','); + i += 5; + } else if (std.mem.startsWith(u8, input[i..], ".")) { + try output.append('.'); + i += 5; + } else if (std.mem.startsWith(u8, input[i..], "/")) { + try output.append('/'); + i += 5; + } else if (std.mem.startsWith(u8, input[i..], ":")) { + try output.append(':'); + i += 5; + } else if (std.mem.startsWith(u8, input[i..], ";")) { + try output.append(';'); + i += 5; + } else { + try output.append(input[i]); + i += 1; + } + } + + return output.toOwnedSlice(); +} + diff --git a/frameworks/Zig/httpz/src/main.zig b/frameworks/Zig/httpz/src/main.zig new file mode 100644 index 00000000000..ae2c1a70ac4 --- /dev/null +++ b/frameworks/Zig/httpz/src/main.zig @@ -0,0 +1,71 @@ +const std = @import("std"); +const builtin = @import("builtin"); +const httpz = @import("httpz"); +const pg = @import("pg"); +const datetimez = @import("datetimez"); +const pool = @import("pool.zig"); + +const endpoints = @import("endpoints.zig"); + +const RndGen = std.rand.DefaultPrng; +const Allocator = std.mem.Allocator; +const Pool = pg.Pool; + +var server: httpz.ServerCtx(*endpoints.Global,*endpoints.Global) = undefined; + +pub fn main() !void { + var gpa = std.heap.GeneralPurposeAllocator(.{ + .thread_safe = true, + }){}; + + const allocator = gpa.allocator(); + + var pg_pool = try pool.initPool(allocator); + defer pg_pool.deinit(); + + var prng = std.rand.DefaultPrng.init(@as(u64, @bitCast(std.time.milliTimestamp()))); + + var global = endpoints.Global{ .pool = pg_pool, .prng = &prng, .allocator = allocator }; + + server = try httpz.ServerApp(*endpoints.Global).init(allocator, .{ + .port = 3000, .address = "0.0.0.0", }, &global); + defer server.deinit(); + + // now that our server is up, we register our intent to handle SIGINT + try std.posix.sigaction(std.posix.SIG.INT, &.{ + .handler = .{.handler = shutdown}, + .mask = std.posix.empty_sigset, + .flags = 0, + }, null); + + var router = server.router(); + router.get("/json", endpoints.json); + router.get("/plaintext", endpoints.plaintext); + router.get("/db", endpoints.db); + router.get("/fortunes", endpoints.fortune); + + std.debug.print("Httpz listening at 0.0.0.0:{d}\n", .{3000}); + + try server.listen(); +} + +fn shutdown(_: c_int) callconv(.C) void { + // this will unblock the server.listen() + server.stop(); +} + +fn notFound(_: *httpz.Request, res: *httpz.Response) !void { + res.status = 404; + + // you can set the body directly to a []u8, but note that the memory + // must be valid beyond your handler. Use the res.arena if you need to allocate + // memory for the body. + res.body = "Not Found"; +} + +// note that the error handler return `void` and not `!void` +fn errorHandler(req: *httpz.Request, res: *httpz.Response, err: anyerror) void { + res.status = 500; + res.body = "Internal Server Error"; + std.log.warn("httpz: unhandled exception for request: {s}\nErr: {}", .{req.url.raw, err}); +} \ No newline at end of file diff --git a/frameworks/Zig/httpz/src/pool.zig b/frameworks/Zig/httpz/src/pool.zig new file mode 100644 index 00000000000..c41cb329540 --- /dev/null +++ b/frameworks/Zig/httpz/src/pool.zig @@ -0,0 +1,87 @@ +const std = @import("std"); +const regex = @import("regex"); +const pg = @import("pg"); + +const Allocator = std.mem.Allocator; +const Pool = pg.Pool; +const ArrayList = std.ArrayList; + +pub fn initPool(allocator: Allocator) !*pg.Pool { + const info = try parsePostgresConnStr(allocator); + //std.debug.print("Connection: {s}:{s}@{s}:{d}/{s}\n", .{ info.username, info.password, info.hostname, info.port, info.database }); + + const pg_pool = try Pool.init(allocator, .{ + .size = 28, + .connect = .{ + .port = info.port, + .host = info.hostname, + }, + .auth = .{ + .username = info.username, + .database = info.database, + .password = info.password, + }, + .timeout = 10_000, + }); + + return pg_pool; +} + +pub const ConnectionInfo = struct { + username: []const u8, + password: []const u8, + hostname: []const u8, + port: u16, + database: []const u8, +}; + +fn addressAsString(address: std.net.Address) ![]const u8 { + const bytes = @as(*const [4]u8, @ptrCast(&address.in.sa.addr)); + + var buffer: [256]u8 = undefined; + var source = std.io.StreamSource{ .buffer = std.io.fixedBufferStream(&buffer) }; + var writer = source.writer(); + + //try writer.writeAll("Hello, World!"); + + try writer.print("{}.{}.{}.{}", .{ + bytes[0], + bytes[1], + bytes[2], + bytes[3], + }); + + const output = source.buffer.getWritten(); + + return output; +} + +fn parsePostgresConnStr(allocator: Allocator) !ConnectionInfo { + const pg_port = try getEnvVar(allocator, "PG_PORT", "5432"); + // std.debug.print("tfb port {s}\n", .{pg_port}); + var port = try std.fmt.parseInt(u16, pg_port, 0); + + if (port == 0) { + port = 5432; + } + + return ConnectionInfo{ + .username = try getEnvVar(allocator, "PG_USER", "benchmarkdbuser"), + .password = try getEnvVar(allocator, "PG_PASS", "benchmarkdbpass"), + .hostname = try getEnvVar(allocator, "PG_HOST", "localhost"), + .port = port, + .database = try getEnvVar(allocator, "PG_DB", "hello_world"), + }; +} + +fn getEnvVar(allocator: Allocator, name: []const u8, default: []const u8) ![]const u8 { + const env_var = std.process.getEnvVarOwned(allocator, name) catch |err| switch (err) { + error.EnvironmentVariableNotFound => return default, + error.OutOfMemory => return err, + error.InvalidWtf8 => return err, + }; + + if (env_var.len == 0) return default; + + return env_var; +} From 7ccad708d0941c82bc7b4972a7c8ca554edee9a2 Mon Sep 17 00:00:00 2001 From: walkor Date: Tue, 22 Oct 2024 22:47:20 +0800 Subject: [PATCH 180/204] [php] Enable jit for workerman and webman (#9258) * Enable jit and remove unnecessary files * Remove reusePort * Add maintainers walkor * Use the latest event extension * Use event-3.1.4 * Add without jit tests * Fix dockerfile name * Add space to display_name * save * Reuseport --- frameworks/PHP/webman/benchmark_config.json | 22 ++++- frameworks/PHP/webman/config.toml | 18 +++++ frameworks/PHP/webman/config/server.php | 3 +- frameworks/PHP/webman/php.ini | 6 +- frameworks/PHP/webman/webman-pgsql.dockerfile | 26 ++++++ frameworks/PHP/webman/webman.dockerfile | 9 ++- .../PHP/workerman/benchmark_config.json | 50 ++++++++---- frameworks/PHP/workerman/config.toml | 25 +++++- frameworks/PHP/workerman/php-jit.ini | 6 +- frameworks/PHP/workerman/php.ini | 2 +- frameworks/PHP/workerman/server-async.php | 80 ------------------- frameworks/PHP/workerman/server.php | 23 ++++-- ...nc.dockerfile => workerman-jit.dockerfile} | 12 +-- .../workerman/workerman-mysql-jit.dockerfile | 26 ++++++ ...kerfile => workerman-pgsql-jit.dockerfile} | 11 +-- .../PHP/workerman/workerman-pgsql.dockerfile | 10 +-- frameworks/PHP/workerman/workerman.dockerfile | 7 +- 17 files changed, 194 insertions(+), 142 deletions(-) create mode 100644 frameworks/PHP/webman/webman-pgsql.dockerfile delete mode 100644 frameworks/PHP/workerman/server-async.php rename frameworks/PHP/workerman/{workerman-async.dockerfile => workerman-jit.dockerfile} (65%) create mode 100644 frameworks/PHP/workerman/workerman-mysql-jit.dockerfile rename frameworks/PHP/workerman/{workerman-php8-jit.dockerfile => workerman-pgsql-jit.dockerfile} (66%) diff --git a/frameworks/PHP/webman/benchmark_config.json b/frameworks/PHP/webman/benchmark_config.json index 864deacb0bf..7e185ce1b24 100644 --- a/frameworks/PHP/webman/benchmark_config.json +++ b/frameworks/PHP/webman/benchmark_config.json @@ -1,9 +1,29 @@ { "framework": "webman", + "maintainers": ["walkor"], "tests": [{ "default": { + "dockerfile": "webman.dockerfile", "json_url": "/json", "plaintext_url": "/plaintext", + "port": 8080, + "approach": "Realistic", + "classification": "Micro", + "database": "Postgres", + "framework": "webman", + "language": "PHP", + "flavor": "PHP7", + "orm": "Raw", + "platform": "workerman", + "webserver": "None", + "os": "Linux", + "database_os": "Linux", + "display_name": "webman", + "notes": "", + "versus": "workerman" + }, + "pgsql": { + "dockerfile": "webman-pgsql.dockerfile", "db_url": "/db", "query_url": "/queries/", "update_url": "/updates/", @@ -20,7 +40,7 @@ "webserver": "None", "os": "Linux", "database_os": "Linux", - "display_name": "webman", + "display_name": "webman-pgsql", "notes": "", "versus": "workerman" } diff --git a/frameworks/PHP/webman/config.toml b/frameworks/PHP/webman/config.toml index b4cfc7e64d6..3aa7a920672 100644 --- a/frameworks/PHP/webman/config.toml +++ b/frameworks/PHP/webman/config.toml @@ -17,3 +17,21 @@ orm = "Raw" platform = "workerman" webserver = "None" versus = "workerman" + + +[pgsql] +urls.plaintext = "/plaintext" +urls.json = "/json" +urls.db = "/db" +urls.query = "/queries/" +urls.update = "/updates/" +urls.fortune = "/fortunes" +approach = "Realistic" +classification = "Micro" +database = "Postgres" +database_os = "Linux" +os = "Linux" +orm = "Raw" +platform = "workerman" +webserver = "None" +versus = "workerman" \ No newline at end of file diff --git a/frameworks/PHP/webman/config/server.php b/frameworks/PHP/webman/config/server.php index 39f256488ef..a9e2686c8dc 100644 --- a/frameworks/PHP/webman/config/server.php +++ b/frameworks/PHP/webman/config/server.php @@ -17,9 +17,10 @@ 'transport' => 'tcp', 'context' => [], 'name' => 'webman', - 'count' => cpu_count() * 4, + 'count' => cpu_count() * ( getenv('TEST_TYPE') === 'default' ? 1 : 4 ), 'user' => '', 'group' => '', + 'reuse_port' => true, 'pid_file' => runtime_path() . '/webman.pid', 'status_file' => runtime_path() . '/webman.status', 'stdout_file' => runtime_path() . '/logs/stdout.log', diff --git a/frameworks/PHP/webman/php.ini b/frameworks/PHP/webman/php.ini index f0c616f9fb2..f4817cc9e3a 100644 --- a/frameworks/PHP/webman/php.ini +++ b/frameworks/PHP/webman/php.ini @@ -1,13 +1,11 @@ +zend_extension=opcache.so opcache.enable=1 opcache.enable_cli=1 opcache.validate_timestamps=0 opcache.save_comments=0 opcache.enable_file_override=1 opcache.huge_code_pages=1 - mysqlnd.collect_statistics = Off - memory_limit = 512M - opcache.jit_buffer_size=128M -opcache.jit=tracing +opcache.jit=tracing \ No newline at end of file diff --git a/frameworks/PHP/webman/webman-pgsql.dockerfile b/frameworks/PHP/webman/webman-pgsql.dockerfile new file mode 100644 index 00000000000..491396785ea --- /dev/null +++ b/frameworks/PHP/webman/webman-pgsql.dockerfile @@ -0,0 +1,26 @@ +FROM ubuntu:24.04 + +ENV TEST_TYPE pgsql + +ARG DEBIAN_FRONTEND=noninteractive + +RUN apt-get update -yqq && apt-get install -yqq software-properties-common > /dev/null +RUN LC_ALL=C.UTF-8 add-apt-repository ppa:ondrej/php > /dev/null && \ + apt-get update -yqq > /dev/null && apt-get upgrade -yqq > /dev/null + +RUN apt-get install -yqq php8.3-cli php8.3-pgsql php8.3-xml > /dev/null + +COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer + +RUN apt-get update -yqq && apt-get install -y php-pear php8.3-dev libevent-dev git > /dev/null +RUN pecl install event-3.1.4 > /dev/null && echo "extension=event.so" > /etc/php/8.3/cli/conf.d/30-event.ini + +ADD ./ /webman +WORKDIR /webman + +RUN composer install --optimize-autoloader --classmap-authoritative --no-dev --quiet +COPY php.ini /etc/php/8.3/cli/conf.d/10-opcache.ini + +EXPOSE 8080 + +CMD php /webman/start.php start diff --git a/frameworks/PHP/webman/webman.dockerfile b/frameworks/PHP/webman/webman.dockerfile index 5b64cd4aa16..20ef9d61064 100644 --- a/frameworks/PHP/webman/webman.dockerfile +++ b/frameworks/PHP/webman/webman.dockerfile @@ -1,4 +1,6 @@ -FROM ubuntu:22.04 +FROM ubuntu:24.04 + +ENV TEST_TYPE default ARG DEBIAN_FRONTEND=noninteractive @@ -11,14 +13,13 @@ RUN apt-get install -yqq php8.3-cli php8.3-pgsql php8.3-xml > /dev/null COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer RUN apt-get update -yqq && apt-get install -y php-pear php8.3-dev libevent-dev git > /dev/null -RUN pecl install event-3.1.3 > /dev/null && echo "extension=event.so" > /etc/php/8.3/cli/conf.d/event.ini - -COPY php.ini /etc/php/8.3/cli/php.ini +RUN pecl install event-3.1.4 > /dev/null && echo "extension=event.so" > /etc/php/8.3/cli/conf.d/30-event.ini ADD ./ /webman WORKDIR /webman RUN composer install --optimize-autoloader --classmap-authoritative --no-dev --quiet +COPY php.ini /etc/php/8.3/cli/conf.d/10-opcache.ini EXPOSE 8080 diff --git a/frameworks/PHP/workerman/benchmark_config.json b/frameworks/PHP/workerman/benchmark_config.json index 68ce09ced79..bcb286db6d8 100644 --- a/frameworks/PHP/workerman/benchmark_config.json +++ b/frameworks/PHP/workerman/benchmark_config.json @@ -1,13 +1,11 @@ { "framework": "workerman", + "maintainers": ["walkor"], "tests": [{ "default": { + "dockerfile": "workerman-jit.dockerfile", "json_url": "/json", "plaintext_url": "/plaintext", - "db_url": "/db", - "query_url": "/query?q=", - "update_url": "/update?q=", - "fortune_url": "/fortunes", "port": 8080, "approach": "Realistic", "classification": "Platform", @@ -20,11 +18,12 @@ "webserver": "None", "os": "Linux", "database_os": "Linux", - "display_name": "workerman", + "display_name": "workerman [jit]", "notes": "", "versus": "php" }, "pgsql": { + "dockerfile": "workerman-pgsql-jit.dockerfile", "db_url": "/db", "query_url": "/query?q=", "update_url": "/update?q=", @@ -41,12 +40,15 @@ "webserver": "None", "os": "Linux", "database_os": "Linux", - "display_name": "workerman-postgres", + "display_name": "workerman [jit, pgsql]", "notes": "", "versus": "php" }, - "async": { + "mysql": { + "dockerfile": "workerman-mysql-jit.dockerfile", "db_url": "/db", + "query_url": "/query?q=", + "update_url": "/update?q=", "fortune_url": "/fortunes", "port": 8080, "approach": "Realistic", @@ -54,22 +56,38 @@ "database": "MySQL", "framework": "workerman", "language": "PHP", - "flavor": "PHP7", + "flavor": "PHP8", "orm": "Raw", "platform": "workerman", "webserver": "None", "os": "Linux", "database_os": "Linux", - "display_name": "workerman-async-db", + "display_name": "workerman [jit, mysql]", "notes": "", - "versus": "php", - "tags": [ - "broken" - ] + "versus": "php" }, - "php8-jit": { + "without-jit": { + "dockerfile": "workerman.dockerfile", "json_url": "/json", "plaintext_url": "/plaintext", + "port": 8080, + "approach": "Realistic", + "classification": "Platform", + "database": "MySQL", + "framework": "workerman", + "language": "PHP", + "flavor": "PHP8", + "orm": "Raw", + "platform": "workerman", + "webserver": "None", + "os": "Linux", + "database_os": "Linux", + "display_name": "workerman", + "notes": "", + "versus": "php" + }, + "pgsql-without-jit": { + "dockerfile": "workerman-pgsql.dockerfile", "db_url": "/db", "query_url": "/query?q=", "update_url": "/update?q=", @@ -86,8 +104,8 @@ "webserver": "None", "os": "Linux", "database_os": "Linux", - "display_name": "workerman-php8-jit", - "notes": "php8 jit", + "display_name": "workerman [pgsql]", + "notes": "", "versus": "php" } }] diff --git a/frameworks/PHP/workerman/config.toml b/frameworks/PHP/workerman/config.toml index 2f3bbffd22c..b2f50bda1a0 100644 --- a/frameworks/PHP/workerman/config.toml +++ b/frameworks/PHP/workerman/config.toml @@ -33,7 +33,7 @@ platform = "workerman" webserver = "None" versus = "php" -[php8-jit] +[mysql] urls.plaintext = "/plaintext" urls.json = "/json" urls.db = "/db" @@ -50,8 +50,12 @@ platform = "workerman" webserver = "None" versus = "php" -[async] +[without-jit] +urls.plaintext = "/plaintext" +urls.json = "/json" urls.db = "/db" +urls.query = "/query?q=" +urls.update = "/update?q=" urls.fortune = "/fortunes" approach = "Realistic" classification = "Platform" @@ -62,3 +66,20 @@ orm = "Raw" platform = "workerman" webserver = "None" versus = "php" + +[pgsql-without-jit] +urls.plaintext = "/plaintext" +urls.json = "/json" +urls.db = "/db" +urls.query = "/query?q=" +urls.update = "/update?q=" +urls.fortune = "/fortunes" +approach = "Realistic" +classification = "Platform" +database = "Postgres" +database_os = "Linux" +os = "Linux" +orm = "Raw" +platform = "workerman" +webserver = "None" +versus = "php" \ No newline at end of file diff --git a/frameworks/PHP/workerman/php-jit.ini b/frameworks/PHP/workerman/php-jit.ini index f0c616f9fb2..f4817cc9e3a 100644 --- a/frameworks/PHP/workerman/php-jit.ini +++ b/frameworks/PHP/workerman/php-jit.ini @@ -1,13 +1,11 @@ +zend_extension=opcache.so opcache.enable=1 opcache.enable_cli=1 opcache.validate_timestamps=0 opcache.save_comments=0 opcache.enable_file_override=1 opcache.huge_code_pages=1 - mysqlnd.collect_statistics = Off - memory_limit = 512M - opcache.jit_buffer_size=128M -opcache.jit=tracing +opcache.jit=tracing \ No newline at end of file diff --git a/frameworks/PHP/workerman/php.ini b/frameworks/PHP/workerman/php.ini index e12bbd2fb0c..f6be852042e 100644 --- a/frameworks/PHP/workerman/php.ini +++ b/frameworks/PHP/workerman/php.ini @@ -7,4 +7,4 @@ opcache.huge_code_pages=1 mysqlnd.collect_statistics = Off -memory_limit = 512M +memory_limit = 512M \ No newline at end of file diff --git a/frameworks/PHP/workerman/server-async.php b/frameworks/PHP/workerman/server-async.php deleted file mode 100644 index ce468df5cd6..00000000000 --- a/frameworks/PHP/workerman/server-async.php +++ /dev/null @@ -1,80 +0,0 @@ -count = (int) shell_exec('nproc') * 2; -$http_worker->onWorkerStart = static function() { - global $mysql; - - $loop = Worker::getEventLoop(); - - $mysql = new React\MySQL\Connection($loop, [ - 'host' => 'tfb-database', - 'dbname' => 'hello_world', - 'user' => 'benchmarkdbuser', - 'passwd' => 'benchmarkdbpass' - ]); - - $mysql->on('error', function($e){ - echo $e; - }); - - $mysql->connect(function ($e) {}); -}; - -$http_worker->onMessage = static function ($connection, $request) { - - global $mysql; - - switch ($request->path()) { - case '/db': - $mysql->query('SELECT id,randomNumber FROM World WHERE id='.mt_rand(1, 10000), - static function ($command) use ($connection) { - $connection->send(new Response(200, ['Content-Type' => 'application/json', 'Date' => gmdate('D, d M Y H:i:s').' GMT'], json_encode($command->resultRows, JSON_NUMERIC_CHECK))); - } - ); - return; - - case '/fortunes': - // By default use 'Content-Type: text/html; charset=utf-8'; - $mysql->query('SELECT id,message FROM Fortune', - static function ($command) use ($connection) { - $arr = $command->resultRows; - foreach ($arr as $row) { - $fortune[$row['id']] = htmlspecialchars($row['message'], ENT_QUOTES, 'UTF-8'); - } - $fortune[0] = 'Additional fortune added at request time.'; - asort($fortune); - - $html = 'Fortunes'; - foreach ($fortune as $id => $message) { - $html .= ""; - } - - $connection->send(new Response(200, ['Date' => gmdate('D, d M Y H:i:s').' GMT'], $html.'
    idmessage
    $id$message
    ')); - - } - ); - return; - - //case '/update': - // Http::header('Content-Type: application/json'); - // return $connection->send(update()); - - //case '/info': - // Http::header('Content-Type: text/plain'); - // ob_start(); - // phpinfo(); - // return $connection->send(ob_get_clean()); - - default: - $connection->send(new Response(200, [], 'Error 404')); - - } -}; - -Worker::runAll(); diff --git a/frameworks/PHP/workerman/server.php b/frameworks/PHP/workerman/server.php index 5a38cf1e0fc..f856790efa9 100644 --- a/frameworks/PHP/workerman/server.php +++ b/frameworks/PHP/workerman/server.php @@ -1,29 +1,38 @@ count = (int) shell_exec('nproc') * 4; -$http_worker->onWorkerStart = static function () { +$http_worker->reusePort = true; +$http_worker->count = $process_count; +$http_worker->onWorkerStart = static function () use ($test_type) { Header::$date = gmdate('D, d M Y H:i:s').' GMT'; Timer::add(1, function() { Header::$date = gmdate('D, d M Y H:i:s').' GMT'; }); - init(); + if ($test_type === 'pgsql') { + DbRaw::init(); + } else { + init(); + } }; $http_worker->onMessage = static function ($connection, $request) { - $connection->send(router($request)); - }; Worker::runAll(); - class Header { public static $date = null; } diff --git a/frameworks/PHP/workerman/workerman-async.dockerfile b/frameworks/PHP/workerman/workerman-jit.dockerfile similarity index 65% rename from frameworks/PHP/workerman/workerman-async.dockerfile rename to frameworks/PHP/workerman/workerman-jit.dockerfile index 3730d43e58e..c90794ab9be 100644 --- a/frameworks/PHP/workerman/workerman-async.dockerfile +++ b/frameworks/PHP/workerman/workerman-jit.dockerfile @@ -1,26 +1,26 @@ FROM ubuntu:24.04 +ENV TEST_TYPE default + ARG DEBIAN_FRONTEND=noninteractive RUN apt-get update -yqq && apt-get install -yqq software-properties-common > /dev/null RUN LC_ALL=C.UTF-8 add-apt-repository ppa:ondrej/php > /dev/null && \ apt-get update -yqq > /dev/null && apt-get upgrade -yqq > /dev/null -RUN apt-get install -yqq php8.3-cli php8.3-mysql > /dev/null +RUN apt-get install -yqq php8.3-cli php8.3-mysql php8.3-xml > /dev/null COPY --from=composer/composer:latest-bin --link /composer /usr/local/bin/composer RUN apt-get install -y php-pear php8.3-dev libevent-dev git > /dev/null && \ - pecl install event-3.1.3 > /dev/null && echo "extension=event.so" > /etc/php/8.3/cli/conf.d/event.ini - -COPY --link php.ini /etc/php/8.3/cli/php.ini + pecl install event-3.1.4 > /dev/null && echo "extension=event.so" > /etc/php/8.3/cli/conf.d/30-event.ini WORKDIR /workerman COPY --link . . -RUN composer require react/mysql "^0.6" --quiet RUN composer install --optimize-autoloader --classmap-authoritative --no-dev --quiet +COPY php-jit.ini /etc/php/8.3/cli/conf.d/10-opcache.ini EXPOSE 8080 -CMD php /workerman/server-async.php start +CMD php /workerman/server.php start diff --git a/frameworks/PHP/workerman/workerman-mysql-jit.dockerfile b/frameworks/PHP/workerman/workerman-mysql-jit.dockerfile new file mode 100644 index 00000000000..7d8fd9e238d --- /dev/null +++ b/frameworks/PHP/workerman/workerman-mysql-jit.dockerfile @@ -0,0 +1,26 @@ +FROM ubuntu:24.04 + +ENV TEST_TYPE mysql + +ARG DEBIAN_FRONTEND=noninteractive + +RUN apt-get update -yqq && apt-get install -yqq software-properties-common > /dev/null +RUN LC_ALL=C.UTF-8 add-apt-repository ppa:ondrej/php > /dev/null && \ + apt-get update -yqq > /dev/null && apt-get upgrade -yqq > /dev/null + +RUN apt-get install -yqq php8.3-cli php8.3-mysql php8.3-xml > /dev/null + +COPY --from=composer/composer:latest-bin --link /composer /usr/local/bin/composer + +RUN apt-get install -y php-pear php8.3-dev libevent-dev git > /dev/null && \ + pecl install event-3.1.4 > /dev/null && echo "extension=event.so" > /etc/php/8.3/cli/conf.d/30-event.ini + +WORKDIR /workerman +COPY --link . . + +RUN composer install --optimize-autoloader --classmap-authoritative --no-dev --quiet +COPY php-jit.ini /etc/php/8.3/cli/conf.d/10-opcache.ini + +EXPOSE 8080 + +CMD php /workerman/server.php start diff --git a/frameworks/PHP/workerman/workerman-php8-jit.dockerfile b/frameworks/PHP/workerman/workerman-pgsql-jit.dockerfile similarity index 66% rename from frameworks/PHP/workerman/workerman-php8-jit.dockerfile rename to frameworks/PHP/workerman/workerman-pgsql-jit.dockerfile index 528a5c312f6..6c4af626cc0 100644 --- a/frameworks/PHP/workerman/workerman-php8-jit.dockerfile +++ b/frameworks/PHP/workerman/workerman-pgsql-jit.dockerfile @@ -1,5 +1,7 @@ FROM ubuntu:24.04 +ENV TEST_TYPE pgsql + ARG DEBIAN_FRONTEND=noninteractive RUN apt-get update -yqq && apt-get install -yqq software-properties-common > /dev/null @@ -11,18 +13,13 @@ RUN apt-get install -yqq php8.3-cli php8.3-pgsql php8.3-xml > /dev/null COPY --from=composer/composer:latest-bin --link /composer /usr/local/bin/composer RUN apt-get install -y php-pear php8.3-dev libevent-dev git > /dev/null && \ - pecl install event-3.1.3 > /dev/null && echo "extension=event.so" > /etc/php/8.3/cli/conf.d/event.ini - -COPY --link php-jit.ini /etc/php/8.3/cli/php.ini + pecl install event-3.1.4 > /dev/null && echo "extension=event.so" > /etc/php/8.3/cli/conf.d/30-event.ini WORKDIR /workerman COPY --link . . -RUN sed -i "s|'/app.php|'/app-pg.php|g" server.php -RUN sed -i "s|init()|DbRaw::init()|g" server.php -RUN sed -i "s|opcache.jit=off|opcache.jit=function|g" /etc/php/8.3/cli/conf.d/10-opcache.ini - RUN composer install --optimize-autoloader --classmap-authoritative --no-dev --quiet +COPY php-jit.ini /etc/php/8.3/cli/conf.d/10-opcache.ini EXPOSE 8080 diff --git a/frameworks/PHP/workerman/workerman-pgsql.dockerfile b/frameworks/PHP/workerman/workerman-pgsql.dockerfile index 826a6a39383..9b1552d354e 100644 --- a/frameworks/PHP/workerman/workerman-pgsql.dockerfile +++ b/frameworks/PHP/workerman/workerman-pgsql.dockerfile @@ -1,5 +1,7 @@ FROM ubuntu:24.04 +ENV TEST_TYPE pgsql + ARG DEBIAN_FRONTEND=noninteractive RUN apt-get update -yqq && apt-get install -yqq software-properties-common > /dev/null @@ -11,17 +13,13 @@ RUN apt-get install -yqq php8.3-cli php8.3-pgsql php8.3-xml > /dev/null COPY --from=composer/composer:latest-bin --link /composer /usr/local/bin/composer RUN apt-get install -y php-pear php8.3-dev libevent-dev git > /dev/null && \ - pecl install event-3.1.3 > /dev/null && echo "extension=event.so" > /etc/php/8.3/cli/conf.d/event.ini - -COPY --link php.ini /etc/php/8.3/cli/php.ini + pecl install event-3.1.4 > /dev/null && echo "extension=event.so" > /etc/php/8.3/cli/conf.d/30-event.ini WORKDIR /workerman COPY --link . . -RUN sed -i "s|'/app.php|'/app-pg.php|g" server.php -RUN sed -i "s|init()|DbRaw::init()|g" server.php - RUN composer install --optimize-autoloader --classmap-authoritative --no-dev --quiet +COPY php.ini /etc/php/8.3/cli/php.ini EXPOSE 8080 diff --git a/frameworks/PHP/workerman/workerman.dockerfile b/frameworks/PHP/workerman/workerman.dockerfile index 5d09ee6362a..a4d9602019e 100644 --- a/frameworks/PHP/workerman/workerman.dockerfile +++ b/frameworks/PHP/workerman/workerman.dockerfile @@ -1,5 +1,7 @@ FROM ubuntu:24.04 +ENV TEST_TYPE default + ARG DEBIAN_FRONTEND=noninteractive RUN apt-get update -yqq && apt-get install -yqq software-properties-common > /dev/null @@ -11,14 +13,13 @@ RUN apt-get install -yqq php8.3-cli php8.3-mysql php8.3-xml > /dev/null COPY --from=composer/composer:latest-bin --link /composer /usr/local/bin/composer RUN apt-get install -y php-pear php8.3-dev libevent-dev git > /dev/null && \ - pecl install event-3.1.3 > /dev/null && echo "extension=event.so" > /etc/php/8.3/cli/conf.d/event.ini - -COPY --link php-jit.ini /etc/php/8.3/cli/php.ini + pecl install event-3.1.4 > /dev/null && echo "extension=event.so" > /etc/php/8.3/cli/conf.d/30-event.ini WORKDIR /workerman COPY --link . . RUN composer install --optimize-autoloader --classmap-authoritative --no-dev --quiet +COPY php.ini /etc/php/8.3/cli/php.ini EXPOSE 8080 From 42acadfb4143d9a92fef09660503af6495f3d52c Mon Sep 17 00:00:00 2001 From: "James R. Perkins" Date: Tue, 22 Oct 2024 07:47:50 -0700 Subject: [PATCH 181/204] Update WildFly to Jakarta EE 10 and the latest version of WildFly. (#9266) Signed-off-by: James R. Perkins --- frameworks/Java/wildfly-ee/pom.xml | 163 +++++++++++------- .../{bootable-jar.cli => wildfly-setup.cli} | 0 .../{ee7 => ee}/jpa/PersistenceResources.java | 8 +- .../{ee7 => ee}/model/Fortune.java | 14 +- .../techempower/{ee7 => ee}/model/World.java | 10 +- .../rest/CatchAllExceptionMapper.java | 8 +- .../{ee7 => ee}/rest/MyApplication.java | 4 +- .../{ee7 => ee}/tests/Fortunes.java | 10 +- .../{ee7 => ee}/tests/JsonSerialization.java | 8 +- .../{ee7 => ee}/tests/MultipleQueries.java | 14 +- .../{ee7 => ee}/tests/PlainText.java | 8 +- .../{ee7 => ee}/tests/SingleQuery.java | 12 +- .../{ee7 => ee}/tests/TestActions.java | 8 +- .../{ee7 => ee}/tests/Updates.java | 12 +- .../techempower/{ee7 => ee}/util/Helpers.java | 0 .../main/resources/META-INF/persistence.xml | 1 - .../src/main/webapp/WEB-INF/web.xml | 6 +- .../Java/wildfly-ee/wildfly-ee.dockerfile | 5 +- 18 files changed, 159 insertions(+), 132 deletions(-) rename frameworks/Java/wildfly-ee/scripts/{bootable-jar.cli => wildfly-setup.cli} (100%) rename frameworks/Java/wildfly-ee/src/main/java/com/techempower/{ee7 => ee}/jpa/PersistenceResources.java (56%) rename frameworks/Java/wildfly-ee/src/main/java/com/techempower/{ee7 => ee}/model/Fortune.java (76%) rename frameworks/Java/wildfly-ee/src/main/java/com/techempower/{ee7 => ee}/model/World.java (74%) rename frameworks/Java/wildfly-ee/src/main/java/com/techempower/{ee7 => ee}/rest/CatchAllExceptionMapper.java (62%) rename frameworks/Java/wildfly-ee/src/main/java/com/techempower/{ee7 => ee}/rest/MyApplication.java (59%) rename frameworks/Java/wildfly-ee/src/main/java/com/techempower/{ee7 => ee}/tests/Fortunes.java (79%) rename frameworks/Java/wildfly-ee/src/main/java/com/techempower/{ee7 => ee}/tests/JsonSerialization.java (81%) rename frameworks/Java/wildfly-ee/src/main/java/com/techempower/{ee7 => ee}/tests/MultipleQueries.java (78%) rename frameworks/Java/wildfly-ee/src/main/java/com/techempower/{ee7 => ee}/tests/PlainText.java (78%) rename frameworks/Java/wildfly-ee/src/main/java/com/techempower/{ee7 => ee}/tests/SingleQuery.java (64%) rename frameworks/Java/wildfly-ee/src/main/java/com/techempower/{ee7 => ee}/tests/TestActions.java (73%) rename frameworks/Java/wildfly-ee/src/main/java/com/techempower/{ee7 => ee}/tests/Updates.java (81%) rename frameworks/Java/wildfly-ee/src/main/java/com/techempower/{ee7 => ee}/util/Helpers.java (100%) diff --git a/frameworks/Java/wildfly-ee/pom.xml b/frameworks/Java/wildfly-ee/pom.xml index c2e6472f6e3..bd77be766bb 100644 --- a/frameworks/Java/wildfly-ee/pom.xml +++ b/frameworks/Java/wildfly-ee/pom.xml @@ -13,27 +13,69 @@ 17 3.9.0 3.3.2 - 8.0 - 26.0.1.Final - 7.0.0.Final - 2.0.6.Final + 10.0.0 + 5.0.1.Final + 8.0.1.Final
    - + + + + jakarta.platform + jakarta.jakartaee-bom + ${version.jakarta.ee} + import + pom + + + + - javax - javaee-api - ${version.javaee.api} + jakarta.annotation + jakarta.annotation-api + provided + + + jakarta.enterprise + jakarta.enterprise.cdi-api provided - - org.glassfish.jaxb - jaxb-runtime - 2.4.0-b180830.0438 + jakarta.enterprise.concurrent + jakarta.enterprise.concurrent-api + provided + + + jakarta.inject + jakarta.inject-api + provided + + + jakarta.json + jakarta.json-api + provided + + + jakarta.persistence + jakarta.persistence-api + provided + + + jakarta.transaction + jakarta.transaction-api + provided + + + jakarta.validation + jakarta.validation-api + provided + + + jakarta.ws.rs + jakarta.ws.rs-api + provided - @@ -50,63 +92,50 @@ maven-compiler-plugin ${version.compiler.plugin} - ${java.version} - ${java.version} ${java.version} + + org.wildfly.plugins + wildfly-maven-plugin + ${version.wildfly-maven-plugin} + + ROOT.war + + + + org.wildfly + wildfly-ee-galleon-pack + + + org.wildfly + wildfly-datasources-galleon-pack + ${version.wildfly.galleon.datasources.feature.pack} + + + + + + org.wildfly.channels + wildfly-ee + + + + + jaxrs-server + jpa + jsf + mysql-driver + + + + + + + + + + - - - - bootable-jar - - false - - - - - org.wildfly.plugins - wildfly-jar-maven-plugin - ${version.wildfly.maven.jar.plugin} - - - - wildfly@maven(org.jboss.universe:community-universe)#${version.wildfly.bootable} - - - org.wildfly - wildfly-datasources-galleon-pack - ${version.wildfly.galleon.datasources.feature.pack} - - - - jaxrs-server - jsf - mysql-driver - - - deployment-scanner - - - - - - - - - - - - - package - - - - - - - - diff --git a/frameworks/Java/wildfly-ee/scripts/bootable-jar.cli b/frameworks/Java/wildfly-ee/scripts/wildfly-setup.cli similarity index 100% rename from frameworks/Java/wildfly-ee/scripts/bootable-jar.cli rename to frameworks/Java/wildfly-ee/scripts/wildfly-setup.cli diff --git a/frameworks/Java/wildfly-ee/src/main/java/com/techempower/ee7/jpa/PersistenceResources.java b/frameworks/Java/wildfly-ee/src/main/java/com/techempower/ee/jpa/PersistenceResources.java similarity index 56% rename from frameworks/Java/wildfly-ee/src/main/java/com/techempower/ee7/jpa/PersistenceResources.java rename to frameworks/Java/wildfly-ee/src/main/java/com/techempower/ee/jpa/PersistenceResources.java index fcdc4aafa0d..aa580b31f68 100644 --- a/frameworks/Java/wildfly-ee/src/main/java/com/techempower/ee7/jpa/PersistenceResources.java +++ b/frameworks/Java/wildfly-ee/src/main/java/com/techempower/ee/jpa/PersistenceResources.java @@ -1,9 +1,9 @@ package com.techempower.ee7.jpa; -import javax.enterprise.context.Dependent; -import javax.enterprise.inject.Produces; -import javax.persistence.EntityManager; -import javax.persistence.PersistenceContext; +import jakarta.enterprise.context.Dependent; +import jakarta.enterprise.inject.Produces; +import jakarta.persistence.EntityManager; +import jakarta.persistence.PersistenceContext; public class PersistenceResources { diff --git a/frameworks/Java/wildfly-ee/src/main/java/com/techempower/ee7/model/Fortune.java b/frameworks/Java/wildfly-ee/src/main/java/com/techempower/ee/model/Fortune.java similarity index 76% rename from frameworks/Java/wildfly-ee/src/main/java/com/techempower/ee7/model/Fortune.java rename to frameworks/Java/wildfly-ee/src/main/java/com/techempower/ee/model/Fortune.java index dce49416f75..7648c05b539 100644 --- a/frameworks/Java/wildfly-ee/src/main/java/com/techempower/ee7/model/Fortune.java +++ b/frameworks/Java/wildfly-ee/src/main/java/com/techempower/ee/model/Fortune.java @@ -2,13 +2,13 @@ import java.io.Serializable; -import javax.persistence.Entity; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.NamedQuery; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.NamedQuery; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; @NamedQuery(name = "allFortunes", query = "SELECT f FROM Fortune f") @Entity diff --git a/frameworks/Java/wildfly-ee/src/main/java/com/techempower/ee7/model/World.java b/frameworks/Java/wildfly-ee/src/main/java/com/techempower/ee/model/World.java similarity index 74% rename from frameworks/Java/wildfly-ee/src/main/java/com/techempower/ee7/model/World.java rename to frameworks/Java/wildfly-ee/src/main/java/com/techempower/ee/model/World.java index 44fd914aee7..1ee3ae0e97a 100644 --- a/frameworks/Java/wildfly-ee/src/main/java/com/techempower/ee7/model/World.java +++ b/frameworks/Java/wildfly-ee/src/main/java/com/techempower/ee/model/World.java @@ -2,11 +2,11 @@ import java.io.Serializable; -import javax.persistence.Entity; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.validation.constraints.NotNull; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.validation.constraints.NotNull; @Entity public class World implements Serializable { diff --git a/frameworks/Java/wildfly-ee/src/main/java/com/techempower/ee7/rest/CatchAllExceptionMapper.java b/frameworks/Java/wildfly-ee/src/main/java/com/techempower/ee/rest/CatchAllExceptionMapper.java similarity index 62% rename from frameworks/Java/wildfly-ee/src/main/java/com/techempower/ee7/rest/CatchAllExceptionMapper.java rename to frameworks/Java/wildfly-ee/src/main/java/com/techempower/ee/rest/CatchAllExceptionMapper.java index 0beb6e85c3d..bc287fda07a 100644 --- a/frameworks/Java/wildfly-ee/src/main/java/com/techempower/ee7/rest/CatchAllExceptionMapper.java +++ b/frameworks/Java/wildfly-ee/src/main/java/com/techempower/ee/rest/CatchAllExceptionMapper.java @@ -1,9 +1,9 @@ package com.techempower.ee7.rest; -import javax.ws.rs.core.Response; -import javax.ws.rs.core.Response.Status; -import javax.ws.rs.ext.ExceptionMapper; -import javax.ws.rs.ext.Provider; +import jakarta.ws.rs.core.Response; +import jakarta.ws.rs.core.Response.Status; +import jakarta.ws.rs.ext.ExceptionMapper; +import jakarta.ws.rs.ext.Provider; @Provider public class CatchAllExceptionMapper implements ExceptionMapper { diff --git a/frameworks/Java/wildfly-ee/src/main/java/com/techempower/ee7/rest/MyApplication.java b/frameworks/Java/wildfly-ee/src/main/java/com/techempower/ee/rest/MyApplication.java similarity index 59% rename from frameworks/Java/wildfly-ee/src/main/java/com/techempower/ee7/rest/MyApplication.java rename to frameworks/Java/wildfly-ee/src/main/java/com/techempower/ee/rest/MyApplication.java index 5c82e49f3b9..c1f912ec17d 100644 --- a/frameworks/Java/wildfly-ee/src/main/java/com/techempower/ee7/rest/MyApplication.java +++ b/frameworks/Java/wildfly-ee/src/main/java/com/techempower/ee/rest/MyApplication.java @@ -1,7 +1,7 @@ package com.techempower.ee7.rest; -import javax.ws.rs.ApplicationPath; -import javax.ws.rs.core.Application; +import jakarta.ws.rs.ApplicationPath; +import jakarta.ws.rs.core.Application; @ApplicationPath("rest") public class MyApplication extends Application { diff --git a/frameworks/Java/wildfly-ee/src/main/java/com/techempower/ee7/tests/Fortunes.java b/frameworks/Java/wildfly-ee/src/main/java/com/techempower/ee/tests/Fortunes.java similarity index 79% rename from frameworks/Java/wildfly-ee/src/main/java/com/techempower/ee7/tests/Fortunes.java rename to frameworks/Java/wildfly-ee/src/main/java/com/techempower/ee/tests/Fortunes.java index 6bbff0fead8..8bd06ae545c 100644 --- a/frameworks/Java/wildfly-ee/src/main/java/com/techempower/ee7/tests/Fortunes.java +++ b/frameworks/Java/wildfly-ee/src/main/java/com/techempower/ee/tests/Fortunes.java @@ -3,11 +3,11 @@ import java.util.Collections; import java.util.List; -import javax.annotation.PostConstruct; -import javax.enterprise.context.RequestScoped; -import javax.inject.Inject; -import javax.inject.Named; -import javax.persistence.EntityManager; +import jakarta.annotation.PostConstruct; +import jakarta.enterprise.context.RequestScoped; +import jakarta.inject.Inject; +import jakarta.inject.Named; +import jakarta.persistence.EntityManager; import com.techempower.ee7.model.Fortune; diff --git a/frameworks/Java/wildfly-ee/src/main/java/com/techempower/ee7/tests/JsonSerialization.java b/frameworks/Java/wildfly-ee/src/main/java/com/techempower/ee/tests/JsonSerialization.java similarity index 81% rename from frameworks/Java/wildfly-ee/src/main/java/com/techempower/ee7/tests/JsonSerialization.java rename to frameworks/Java/wildfly-ee/src/main/java/com/techempower/ee/tests/JsonSerialization.java index ad5d947b042..019afc50fc7 100644 --- a/frameworks/Java/wildfly-ee/src/main/java/com/techempower/ee7/tests/JsonSerialization.java +++ b/frameworks/Java/wildfly-ee/src/main/java/com/techempower/ee/tests/JsonSerialization.java @@ -1,9 +1,9 @@ package com.techempower.ee7.tests; -import javax.ws.rs.GET; -import javax.ws.rs.Path; -import javax.ws.rs.Produces; -import javax.ws.rs.core.MediaType; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.core.MediaType; @Path("/json") public class JsonSerialization { diff --git a/frameworks/Java/wildfly-ee/src/main/java/com/techempower/ee7/tests/MultipleQueries.java b/frameworks/Java/wildfly-ee/src/main/java/com/techempower/ee/tests/MultipleQueries.java similarity index 78% rename from frameworks/Java/wildfly-ee/src/main/java/com/techempower/ee7/tests/MultipleQueries.java rename to frameworks/Java/wildfly-ee/src/main/java/com/techempower/ee/tests/MultipleQueries.java index 936ddfb4b04..fbd764af7ee 100644 --- a/frameworks/Java/wildfly-ee/src/main/java/com/techempower/ee7/tests/MultipleQueries.java +++ b/frameworks/Java/wildfly-ee/src/main/java/com/techempower/ee/tests/MultipleQueries.java @@ -3,13 +3,13 @@ import java.util.ArrayList; import java.util.List; -import javax.inject.Inject; -import javax.persistence.EntityManager; -import javax.ws.rs.GET; -import javax.ws.rs.Path; -import javax.ws.rs.Produces; -import javax.ws.rs.QueryParam; -import javax.ws.rs.core.MediaType; +import jakarta.inject.Inject; +import jakarta.persistence.EntityManager; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.QueryParam; +import jakarta.ws.rs.core.MediaType; import com.techempower.ee7.model.World; import com.techempower.ee7.util.Helpers; diff --git a/frameworks/Java/wildfly-ee/src/main/java/com/techempower/ee7/tests/PlainText.java b/frameworks/Java/wildfly-ee/src/main/java/com/techempower/ee/tests/PlainText.java similarity index 78% rename from frameworks/Java/wildfly-ee/src/main/java/com/techempower/ee7/tests/PlainText.java rename to frameworks/Java/wildfly-ee/src/main/java/com/techempower/ee/tests/PlainText.java index f40da2ab7da..7ce9f37f3b9 100644 --- a/frameworks/Java/wildfly-ee/src/main/java/com/techempower/ee7/tests/PlainText.java +++ b/frameworks/Java/wildfly-ee/src/main/java/com/techempower/ee/tests/PlainText.java @@ -1,9 +1,9 @@ package com.techempower.ee7.tests; -import javax.ws.rs.GET; -import javax.ws.rs.Path; -import javax.ws.rs.Produces; -import javax.ws.rs.core.MediaType; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.core.MediaType; @Path("/plaintext") public class PlainText { diff --git a/frameworks/Java/wildfly-ee/src/main/java/com/techempower/ee7/tests/SingleQuery.java b/frameworks/Java/wildfly-ee/src/main/java/com/techempower/ee/tests/SingleQuery.java similarity index 64% rename from frameworks/Java/wildfly-ee/src/main/java/com/techempower/ee7/tests/SingleQuery.java rename to frameworks/Java/wildfly-ee/src/main/java/com/techempower/ee/tests/SingleQuery.java index 30279ae4295..517ad710f45 100644 --- a/frameworks/Java/wildfly-ee/src/main/java/com/techempower/ee7/tests/SingleQuery.java +++ b/frameworks/Java/wildfly-ee/src/main/java/com/techempower/ee/tests/SingleQuery.java @@ -1,11 +1,11 @@ package com.techempower.ee7.tests; -import javax.inject.Inject; -import javax.persistence.EntityManager; -import javax.ws.rs.GET; -import javax.ws.rs.Path; -import javax.ws.rs.Produces; -import javax.ws.rs.core.MediaType; +import jakarta.inject.Inject; +import jakarta.persistence.EntityManager; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.core.MediaType; import com.techempower.ee7.model.World; import com.techempower.ee7.util.Helpers; diff --git a/frameworks/Java/wildfly-ee/src/main/java/com/techempower/ee7/tests/TestActions.java b/frameworks/Java/wildfly-ee/src/main/java/com/techempower/ee/tests/TestActions.java similarity index 73% rename from frameworks/Java/wildfly-ee/src/main/java/com/techempower/ee7/tests/TestActions.java rename to frameworks/Java/wildfly-ee/src/main/java/com/techempower/ee/tests/TestActions.java index 9302373516c..d3847c9b661 100644 --- a/frameworks/Java/wildfly-ee/src/main/java/com/techempower/ee7/tests/TestActions.java +++ b/frameworks/Java/wildfly-ee/src/main/java/com/techempower/ee/tests/TestActions.java @@ -1,9 +1,9 @@ package com.techempower.ee7.tests; -import javax.enterprise.context.RequestScoped; -import javax.inject.Inject; -import javax.persistence.EntityManager; -import javax.transaction.Transactional; +import jakarta.enterprise.context.RequestScoped; +import jakarta.inject.Inject; +import jakarta.persistence.EntityManager; +import jakarta.transaction.Transactional; import com.techempower.ee7.model.World; import com.techempower.ee7.util.Helpers; diff --git a/frameworks/Java/wildfly-ee/src/main/java/com/techempower/ee7/tests/Updates.java b/frameworks/Java/wildfly-ee/src/main/java/com/techempower/ee/tests/Updates.java similarity index 81% rename from frameworks/Java/wildfly-ee/src/main/java/com/techempower/ee7/tests/Updates.java rename to frameworks/Java/wildfly-ee/src/main/java/com/techempower/ee/tests/Updates.java index b041f24c939..5c3879bc363 100644 --- a/frameworks/Java/wildfly-ee/src/main/java/com/techempower/ee7/tests/Updates.java +++ b/frameworks/Java/wildfly-ee/src/main/java/com/techempower/ee/tests/Updates.java @@ -3,12 +3,12 @@ import java.util.ArrayList; import java.util.List; -import javax.inject.Inject; -import javax.ws.rs.GET; -import javax.ws.rs.Path; -import javax.ws.rs.Produces; -import javax.ws.rs.QueryParam; -import javax.ws.rs.core.MediaType; +import jakarta.inject.Inject; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.QueryParam; +import jakarta.ws.rs.core.MediaType; import com.techempower.ee7.model.World; import com.techempower.ee7.util.Helpers; diff --git a/frameworks/Java/wildfly-ee/src/main/java/com/techempower/ee7/util/Helpers.java b/frameworks/Java/wildfly-ee/src/main/java/com/techempower/ee/util/Helpers.java similarity index 100% rename from frameworks/Java/wildfly-ee/src/main/java/com/techempower/ee7/util/Helpers.java rename to frameworks/Java/wildfly-ee/src/main/java/com/techempower/ee/util/Helpers.java diff --git a/frameworks/Java/wildfly-ee/src/main/resources/META-INF/persistence.xml b/frameworks/Java/wildfly-ee/src/main/resources/META-INF/persistence.xml index 2ac545e5dde..ff728916fe5 100644 --- a/frameworks/Java/wildfly-ee/src/main/resources/META-INF/persistence.xml +++ b/frameworks/Java/wildfly-ee/src/main/resources/META-INF/persistence.xml @@ -6,7 +6,6 @@ NONE - diff --git a/frameworks/Java/wildfly-ee/src/main/webapp/WEB-INF/web.xml b/frameworks/Java/wildfly-ee/src/main/webapp/WEB-INF/web.xml index 96378e310c9..126c5588694 100644 --- a/frameworks/Java/wildfly-ee/src/main/webapp/WEB-INF/web.xml +++ b/frameworks/Java/wildfly-ee/src/main/webapp/WEB-INF/web.xml @@ -8,7 +8,7 @@ Faces Servlet - javax.faces.webapp.FacesServlet + jakarta.faces.webapp.FacesServlet 1 @@ -18,12 +18,12 @@ - javax.faces.STATE_SAVING_METHOD + jakarta.faces.STATE_SAVING_METHOD client - javax.faces.PROJECT_STAGE + jakarta.faces.PROJECT_STAGE Production diff --git a/frameworks/Java/wildfly-ee/wildfly-ee.dockerfile b/frameworks/Java/wildfly-ee/wildfly-ee.dockerfile index ec4a1c6e063..b04e261e64d 100644 --- a/frameworks/Java/wildfly-ee/wildfly-ee.dockerfile +++ b/frameworks/Java/wildfly-ee/wildfly-ee.dockerfile @@ -1,9 +1,8 @@ FROM maven:3-openjdk-17 WORKDIR /wildfly EXPOSE 8080 -ENV MAVEN_OPTS="--add-exports=java.xml/com.sun.org.apache.xerces.internal.parsers=ALL-UNNAMED --add-exports=java.xml/com.sun.org.apache.xerces.internal.util=ALL-UNNAMED" COPY src src COPY scripts scripts COPY pom.xml pom.xml -RUN mvn clean package -P bootable-jar -CMD java -Djava.net.preferIPv4Stack=true -XX:SoftMaxHeapSize=18g -Xmx24g -XX:+UseZGC -jar target/wildfly-ee-bootable.jar +RUN mvn clean package wildfly:package +CMD JAVA_OPTS="-Djava.net.preferIPv4Stack=true -XX:SoftMaxHeapSize=18g -Xmx24g -XX:+UseZGC" ./target/server/bin/standalone.sh From 3d7db350d2b6aa138f0d56a4b7cb57f9781acdce Mon Sep 17 00:00:00 2001 From: DravenK Date: Tue, 22 Oct 2024 22:48:11 +0800 Subject: [PATCH 182/204] Add Zig Zinc framework (#9289) * Adding Zinc framework * Update num_threads and fixed headers * Update dependency * Update build command * Update Zinc documentation * Run workflow * Update Zinc approach * Update zinc Allocator and plaintext test * Update zinc dependencies * bug fix * Fixed zinc dependencies and port --- frameworks/Zig/zinc/.gitignore | 2 + frameworks/Zig/zinc/README.md | 32 ++++++++++ frameworks/Zig/zinc/benchmark_config.json | 26 ++++++++ frameworks/Zig/zinc/build.zig | 78 +++++++++++++++++++++++ frameworks/Zig/zinc/build.zig.zon | 27 ++++++++ frameworks/Zig/zinc/run.sh | 3 + frameworks/Zig/zinc/src/main.zig | 43 +++++++++++++ frameworks/Zig/zinc/zinc.dockerfile | 21 ++++++ 8 files changed, 232 insertions(+) create mode 100644 frameworks/Zig/zinc/.gitignore create mode 100755 frameworks/Zig/zinc/README.md create mode 100755 frameworks/Zig/zinc/benchmark_config.json create mode 100644 frameworks/Zig/zinc/build.zig create mode 100644 frameworks/Zig/zinc/build.zig.zon create mode 100644 frameworks/Zig/zinc/run.sh create mode 100644 frameworks/Zig/zinc/src/main.zig create mode 100644 frameworks/Zig/zinc/zinc.dockerfile diff --git a/frameworks/Zig/zinc/.gitignore b/frameworks/Zig/zinc/.gitignore new file mode 100644 index 00000000000..170dc0f1403 --- /dev/null +++ b/frameworks/Zig/zinc/.gitignore @@ -0,0 +1,2 @@ +zig-cache/**/*', +zig-out: 'zig-out/**/*', diff --git a/frameworks/Zig/zinc/README.md b/frameworks/Zig/zinc/README.md new file mode 100755 index 00000000000..acf0f93bbcb --- /dev/null +++ b/frameworks/Zig/zinc/README.md @@ -0,0 +1,32 @@ +# [Zinc](https://zinc.zon.dev) web framework + +## Description + +Zinc is a web framework written in pure Zig with a focus on high performance, usability, security, and extensibility. + +* [Documentation](https://zinc.zon.dev/) + +### Some features are: +- **Fast** +- **Custom allocator** +- **Multithreading** +- **Middleware** +- **Routes grouping** +- **Rendering built-in** +- **Extensible** +- **Suite of unit tests** +- **Usability** + +## Important Libraries +The tests were run with: +* [Software](https://zinc.zon.dev/) +* [Example](https://github.com/zon-dev/zinc-examples) + +## Test URLs +### JSON + +http://localhost:8080/json + +### PLAINTEXT + +http://localhost:8080/plaintext diff --git a/frameworks/Zig/zinc/benchmark_config.json b/frameworks/Zig/zinc/benchmark_config.json new file mode 100755 index 00000000000..2e2e874ba2d --- /dev/null +++ b/frameworks/Zig/zinc/benchmark_config.json @@ -0,0 +1,26 @@ +{ + "framework": "zinc", + "tests": [ + { + "default": { + "json_url": "/json", + "plaintext_url": "/plaintext", + "port": 3000, + "approach": "Realistic", + "classification": "Fullstack", + "database": "None", + "framework": "Zinc", + "language": "Zig", + "flavor": "None", + "orm": "None", + "platform": "None", + "webserver": "None", + "os": "Linux", + "database_os": "Linux", + "display_name": "Zinc", + "notes": "", + "versus": "None" + } + } + ] +} diff --git a/frameworks/Zig/zinc/build.zig b/frameworks/Zig/zinc/build.zig new file mode 100644 index 00000000000..e5be63940e5 --- /dev/null +++ b/frameworks/Zig/zinc/build.zig @@ -0,0 +1,78 @@ +const std = @import("std"); + +// Although this function looks imperative, note that its job is to +// declaratively construct a build graph that will be executed by an external +// runner. +pub fn build(b: *std.Build) void { + // Standard target options allows the person running `zig build` to choose + // what target to build for. Here we do not override the defaults, which + // means any target is allowed, and the default is native. Other options + // for restricting supported target set are available. + const target = b.standardTargetOptions(.{}); + + // Standard optimization options allow the person running `zig build` to select + // between Debug, ReleaseSafe, ReleaseFast, and ReleaseSmall. Here we do not + // set a preferred release mode, allowing the user to decide how to optimize. + const optimize = b.standardOptimizeOption(.{}); + + const exe = b.addExecutable(.{ + .name = "zinc", + .root_source_file = b.path("src/main.zig"), + .target = target, + .optimize = optimize, + }); + + const zinc = b.dependency("zinc", .{ + .target = target, + .optimize = optimize, + }); + exe.root_module.addImport("zinc", zinc.module("zinc")); + + const datetime = b.dependency("zig-datetime", .{ + .target = target, + .optimize = optimize, + }); + exe.root_module.addImport("datetime", datetime.module("zig-datetime")); + + // This declares intent for the executable to be installed into the + // standard location when the user invokes the "install" step (the default + // step when running `zig build`). + b.installArtifact(exe); + + // This *creates* a Run step in the build graph, to be executed when another + // step is evaluated that depends on it. The next line below will establish + // such a dependency. + const run_cmd = b.addRunArtifact(exe); + + // By making the run step depend on the install step, it will be run from the + // installation directory rather than directly from within the cache directory. + // This is not necessary, however, if the application depends on other installed + // files, this ensures they will be present and in the expected location. + run_cmd.step.dependOn(b.getInstallStep()); + + // This allows the user to pass arguments to the application in the build + // command itself, like this: `zig build run -- arg1 arg2 etc` + if (b.args) |args| { + run_cmd.addArgs(args); + } + + // This creates a build step. It will be visible in the `zig build --help` menu, + // and can be selected like this: `zig build run` + // This will evaluate the `run` step rather than the default, which is "install". + const run_step = b.step("run", "Run the app"); + run_step.dependOn(&run_cmd.step); + + const exe_unit_tests = b.addTest(.{ + .root_source_file = b.path("src/main.zig"), + .target = target, + .optimize = optimize, + }); + + const run_exe_unit_tests = b.addRunArtifact(exe_unit_tests); + + // Similar to creating the run step earlier, this exposes a `test` step to + // the `zig build --help` menu, providing a way for the user to request + // running the unit tests. + const test_step = b.step("test", "Run unit tests"); + test_step.dependOn(&run_exe_unit_tests.step); +} diff --git a/frameworks/Zig/zinc/build.zig.zon b/frameworks/Zig/zinc/build.zig.zon new file mode 100644 index 00000000000..9a4c8f302cf --- /dev/null +++ b/frameworks/Zig/zinc/build.zig.zon @@ -0,0 +1,27 @@ +.{ + .name = "zinc", + .version = "0.1.0", + .dependencies = .{ + .zinc = .{ + .url = "https://github.com/zon-dev/zinc/archive/refs/tags/0.1.0-beta.5.tar.gz", + .hash = "12201444aa36b4a83f262f319e7c17ccdcff9fbde2efbeb5fc94f1a07eda0d99428e", + }, + .@"zig-datetime" = .{ + .url = "git+https://github.com/frmdstryr/zig-datetime#70aebf28fb3e137cd84123a9349d157a74708721", + .hash = "122077215ce36e125a490e59ec1748ffd4f6ba00d4d14f7308978e5360711d72d77f", + }, + .pg = .{ + .url = "git+https://github.com/karlseguin/pg.zig#21db2306aff657802f9cb10a1e7f8fe9c33e7990", + .hash = "1220df8995ceea78a4a37a505fc779ded75725d0606c33fded26103953524dde1619", + }, + .mustache = .{ + .url = "git+https://github.com/batiati/mustache-zig#ac358646ab9e6123285b90c947ecd40f7966d531", + .hash = "1220cd6e1b49bdd0a568682957dab9a6864554755908f7de990ec7c050f58cf41da2", + }, + }, + .paths = .{ + "build.zig", + "build.zig.zon", + "src", + }, +} diff --git a/frameworks/Zig/zinc/run.sh b/frameworks/Zig/zinc/run.sh new file mode 100644 index 00000000000..639c542fc3e --- /dev/null +++ b/frameworks/Zig/zinc/run.sh @@ -0,0 +1,3 @@ +echo "Waiting for Zinc framework to start..." + +zinc \ No newline at end of file diff --git a/frameworks/Zig/zinc/src/main.zig b/frameworks/Zig/zinc/src/main.zig new file mode 100644 index 00000000000..f06104dc4f1 --- /dev/null +++ b/frameworks/Zig/zinc/src/main.zig @@ -0,0 +1,43 @@ +const std = @import("std"); +const zinc = @import("zinc"); +const Datetime = @import("datetime").datetime.Datetime; + +pub fn main() !void { + var gpa = std.heap.GeneralPurposeAllocator(.{ .thread_safe = true }){}; + defer _ = gpa.deinit(); + const allocator = gpa.allocator(); + + var z = try zinc.init(.{ + .port = 3000, + .allocator = allocator, + .num_threads = 16 * @as(u8, @intCast(std.Thread.getCpuCount() catch 1)), + }); + defer z.deinit(); + + var router = z.getRouter(); + try router.use(&.{setupHeader}); + try router.get("/json", json); + try router.get("/plaintext", plaintext); + + try z.run(); +} + +fn plaintext(ctx: *zinc.Context) anyerror!void { + try ctx.setHeader("Content-Type", "text/plain; charset=utf-8"); + try ctx.setBody("Hello, world!"); +} + +fn json(ctx: *zinc.Context) anyerror!void { + try ctx.json(.{ .message = "Hello, World!" }, .{}); +} + +fn setupHeader(ctx: *zinc.Context) anyerror!void { + try ctx.setHeader("Server", "Zinc"); + + const now = Datetime.now(); + const now_str = try now.formatHttp(ctx.allocator); + // defer ctx.allocator.free(now_str); + + // The time is now: Fri, 20 Dec 2019 22:03:02 UTC + try ctx.setHeader("date", now_str); +} diff --git a/frameworks/Zig/zinc/zinc.dockerfile b/frameworks/Zig/zinc/zinc.dockerfile new file mode 100644 index 00000000000..11b64881d2c --- /dev/null +++ b/frameworks/Zig/zinc/zinc.dockerfile @@ -0,0 +1,21 @@ +FROM fedora:40 AS build + +WORKDIR /zinc + +COPY src src +COPY run.sh run.sh + +COPY build.zig.zon build.zig.zon +COPY build.zig build.zig + +RUN dnf install -y zig +RUN zig version +RUN zig build -Doptimize=ReleaseFast +RUN cp /zinc/zig-out/bin/zinc /usr/local/bin + +EXPOSE 3000 +ARG BENCHMARK_ENV +ARG TFB_TEST_DATABASE +ARG TFB_TEST_NAME + +CMD ["sh", "run.sh"] From 03c56d5f144d9080b5cb070d1fbd9f8b2e8aaf32 Mon Sep 17 00:00:00 2001 From: pavelmash <7467039+pavelmash@users.noreply.github.com> Date: Sun, 27 Oct 2024 18:27:19 +0200 Subject: [PATCH 183/204] [mORMot] - upgrade to mORmot@2.3.stable + CMem (#9350) Co-authored-by: pavel.mash --- frameworks/Pascal/mormot/setup_and_build.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/frameworks/Pascal/mormot/setup_and_build.sh b/frameworks/Pascal/mormot/setup_and_build.sh index 8f2d533127f..62bd68746f8 100755 --- a/frameworks/Pascal/mormot/setup_and_build.sh +++ b/frameworks/Pascal/mormot/setup_and_build.sh @@ -27,7 +27,7 @@ rm -rf ./libs mkdir -p ./libs/mORMot/static # echo "Getting the latest pre-release URL..." # USED_TAG=$(wget -qO- https://api.github.com/repos/synopse/mORMot2/releases/latest | jq -r '.tag_name') -USED_TAG="2.2.stable" +USED_TAG="2.3.stable" echo "Used release tag $USED_TAG" URL="https://github.com/synopse/mORMot2/releases/download/$USED_TAG/mormot2static.tgz" @@ -35,8 +35,8 @@ echo "Download statics from $URL ..." wget -qO- "$URL" | tar -xz -C ./libs/mORMot/static # uncomment for fixed commit URL -URL=https://github.com/synopse/mORMot2/tarball/6dc09ceca456931384857b383ed61b63f11f3be7 -#URL="https://api.github.com/repos/synopse/mORMot2/tarball/$USED_TAG" +#URL=https://github.com/synopse/mORMot2/tarball/6dc09ceca456931384857b383ed61b63f11f3be7 +URL="https://api.github.com/repos/synopse/mORMot2/tarball/$USED_TAG" echo "Download and unpacking mORMot sources from $URL ..." wget -qO- "$URL" | tar -xz -C ./libs/mORMot --strip-components=1 @@ -80,7 +80,7 @@ fpc -MDelphi -Sci -Ci -O3 -g -gl -gw2 -Xg -k'-rpath=$ORIGIN' -k-L$BIN \ -Fu"$MSRC/core" -Fu"$MSRC/db" -Fu"$MSRC/rest" -Fu"$MSRC/crypt" \ -Fu"$MSRC/app" -Fu"$MSRC/net" -Fu"$MSRC/lib" -Fu"$MSRC/orm" -Fu"$MSRC/soa" \ -FU"$BIN/fpc-$ARCH_TG/.dcu" -FE"$BIN/fpc-$ARCH_TG" -o"$BIN/fpc-$ARCH_TG/$dest_fn" \ - -dFPC_X64MM -dFPCMM_SERVER \ + -dFPC_LIBCMM -dFPC_LIBCMM_NOMSIZE \ -B -Se1 "./src/raw.pas" | grep "[Warning|Error|Fatal]:" script_successful \ No newline at end of file From 7caeea0d2c060e08d0fe7306887fe852e31805c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=A5=BF=E4=B8=9C?= Date: Mon, 28 Oct 2024 00:27:38 +0800 Subject: [PATCH 184/204] [Java] Update Solon Version To 3.0.2 (#9351) * Update Solon Version To 2.9.1 * Update Solon Version To 2.9.1 * Update Solon Jdk To 21 * Update Solon Jdk To 21 * Update Solon Jdk To 21 * Update Solon Jdk To 21 * Update Solon Jdk To 21 * Update Solon Version To 2.9.2 * Add Solon-Virtual * Remove solon-virtual * Update Solon Version To 3.0.2 --- frameworks/Java/solon/README.md | 2 +- frameworks/Java/solon/pom.xml | 8 +++----- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/frameworks/Java/solon/README.md b/frameworks/Java/solon/README.md index f2370ab2305..49d4aef9fe8 100644 --- a/frameworks/Java/solon/README.md +++ b/frameworks/Java/solon/README.md @@ -10,7 +10,7 @@ This is the solon portion of a [benchmarking test suite](../) comparing a variet ## Versions * [Java OpenJDK 21](http://openjdk.java.net/) -* [solon 2.9.1](https://github.com/noear/solon) +* [solon 3.0.2](https://github.com/noear/solon) ## Test URLs diff --git a/frameworks/Java/solon/pom.xml b/frameworks/Java/solon/pom.xml index 035ad60951a..0c9d8d570ce 100644 --- a/frameworks/Java/solon/pom.xml +++ b/frameworks/Java/solon/pom.xml @@ -5,7 +5,7 @@ org.noear solon-parent - 2.9.2 + 3.0.2 hello @@ -20,14 +20,12 @@ org.noear - solon.boot.smarthttp - ${solon.version} + solon-boot-smarthttp org.noear - solon.serialization.fastjson2 - ${solon.version} + solon-serialization-snack3 From 4c793a6af8f146de97058380380f4c5af184c070 Mon Sep 17 00:00:00 2001 From: Petrik de Heus Date: Sun, 27 Oct 2024 17:27:59 +0100 Subject: [PATCH 185/204] [ruby/sinatra-sequel] Remove some test variations (#9359) Don't run every permutation as there isn't a lot of variation. Limit to running: - Puma with MySQL (the default) - Puma with Postgres - Unicorn with Postgres - Passenger with Postgres This remove the following variations which were slower that their Postgres alternative: - Unicorn with MySQL - Passenger with MySQL --- .../Ruby/sinatra-sequel/benchmark_config.json | 40 ------------------- .../sinatra-sequel-passenger-mri.dockerfile | 26 ------------ .../sinatra-sequel-unicorn-mri.dockerfile | 19 --------- 3 files changed, 85 deletions(-) delete mode 100644 frameworks/Ruby/sinatra-sequel/sinatra-sequel-passenger-mri.dockerfile delete mode 100644 frameworks/Ruby/sinatra-sequel/sinatra-sequel-unicorn-mri.dockerfile diff --git a/frameworks/Ruby/sinatra-sequel/benchmark_config.json b/frameworks/Ruby/sinatra-sequel/benchmark_config.json index c16da1e0e26..9a267813727 100644 --- a/frameworks/Ruby/sinatra-sequel/benchmark_config.json +++ b/frameworks/Ruby/sinatra-sequel/benchmark_config.json @@ -42,26 +42,6 @@ "versus": "rack-sequel-postgres-puma-mri", "notes": "" }, - "passenger-mri": { - "db_url": "/db", - "query_url": "/queries?queries=", - "fortune_url": "/fortunes", - "update_url": "/updates?queries=", - "port": 8080, - "approach": "Realistic", - "classification": "Micro", - "database": "MySQL", - "framework": "sinatra", - "language": "Ruby", - "orm": "Full", - "platform": "Rack", - "webserver": "Passenger", - "os": "Linux", - "database_os": "Linux", - "display_name": "sinatra-sequel-passenger-mri", - "versus": "rack-sequel-passenger-mri", - "notes": "" - }, "postgres-passenger-mri": { "db_url": "/db", "query_url": "/queries?queries=", @@ -82,26 +62,6 @@ "versus": "rack-sequel-postgres-passenger-mri", "notes": "" }, - "unicorn-mri": { - "db_url": "/db", - "query_url": "/queries?queries=", - "fortune_url": "/fortunes", - "update_url": "/updates?queries=", - "port": 8080, - "approach": "Realistic", - "classification": "Micro", - "database": "MySQL", - "framework": "sinatra", - "language": "Ruby", - "orm": "Full", - "platform": "Rack", - "webserver": "Unicorn", - "os": "Linux", - "database_os": "Linux", - "display_name": "sinatra-sequel-unicorn-mri", - "versus": "rack-sequel-unicorn-mri", - "notes": "" - }, "postgres-unicorn-mri": { "db_url": "/db", "query_url": "/queries?queries=", diff --git a/frameworks/Ruby/sinatra-sequel/sinatra-sequel-passenger-mri.dockerfile b/frameworks/Ruby/sinatra-sequel/sinatra-sequel-passenger-mri.dockerfile deleted file mode 100644 index 39bd11758da..00000000000 --- a/frameworks/Ruby/sinatra-sequel/sinatra-sequel-passenger-mri.dockerfile +++ /dev/null @@ -1,26 +0,0 @@ -FROM ruby:3.3 - -ENV RUBY_YJIT_ENABLE=1 - -# Use Jemalloc -RUN apt-get update && \ - apt-get install -y --no-install-recommends libjemalloc2 -ENV LD_PRELOAD=libjemalloc.so.2 - -ADD ./ /sinatra-sequel -WORKDIR /sinatra-sequel - -RUN bundle install --jobs=4 --gemfile=/sinatra-sequel/Gemfile - -# TODO: https://github.com/phusion/passenger/issues/1916 -ENV _PASSENGER_FORCE_HTTP_SESSION=true -ENV DBTYPE=mysql - -RUN ruby -r /sinatra-sequel/config/auto_tune -e 'puts auto_tune.first' > instances - -EXPOSE 8080 - -CMD bundle exec passenger start --log-level 1 \ - --engine builtin --disable-turbocaching --disable-security-update-check \ - --spawn-method direct --max-pool-size $(cat instances) --min-instances $(cat instances) --max-request-queue-size 1024 \ - --address 0.0.0.0 --port 8080 --environment production diff --git a/frameworks/Ruby/sinatra-sequel/sinatra-sequel-unicorn-mri.dockerfile b/frameworks/Ruby/sinatra-sequel/sinatra-sequel-unicorn-mri.dockerfile deleted file mode 100644 index c3e2bc7de13..00000000000 --- a/frameworks/Ruby/sinatra-sequel/sinatra-sequel-unicorn-mri.dockerfile +++ /dev/null @@ -1,19 +0,0 @@ -FROM ruby:3.4-rc - -ENV RUBY_YJIT_ENABLE=1 - -# Use Jemalloc -RUN apt-get update && \ - apt-get install -y --no-install-recommends libjemalloc2 -ENV LD_PRELOAD=libjemalloc.so.2 - -ADD ./ /sinatra-sequel -WORKDIR /sinatra-sequel - -RUN bundle install --jobs=4 --gemfile=/sinatra-sequel/Gemfile - -ENV DBTYPE=mysql - -EXPOSE 8080 - -CMD bundle exec unicorn -c config/mri_unicorn.rb -o 0.0.0.0 -p 8080 -E production From e3bd32520f45b6310062ec532bbcf2e84984d2dc Mon Sep 17 00:00:00 2001 From: Petrik de Heus Date: Sun, 27 Oct 2024 17:28:07 +0100 Subject: [PATCH 186/204] [ruby/sinatra] Remove some test variations (#9361) Don't run every permutation as there isn't a lot of variation. Limit to running: - Puma with MySQL (the default) - Puma with Postgres - Unicorn with Postgres - Passenger with Postgres This remove the following variations which were slower that their Postgres alternative: - Unicorn with MySQL - Passenger with MySQL --- frameworks/Ruby/sinatra/benchmark_config.json | 44 ------------------- .../sinatra/sinatra-passenger-mri.dockerfile | 26 ----------- .../sinatra/sinatra-unicorn-mri.dockerfile | 19 -------- 3 files changed, 89 deletions(-) delete mode 100644 frameworks/Ruby/sinatra/sinatra-passenger-mri.dockerfile delete mode 100644 frameworks/Ruby/sinatra/sinatra-unicorn-mri.dockerfile diff --git a/frameworks/Ruby/sinatra/benchmark_config.json b/frameworks/Ruby/sinatra/benchmark_config.json index 166a2e9e2bf..2c0be64ed47 100644 --- a/frameworks/Ruby/sinatra/benchmark_config.json +++ b/frameworks/Ruby/sinatra/benchmark_config.json @@ -44,28 +44,6 @@ "versus": "rack-postgres-puma-mri", "notes": "" }, - "passenger-mri": { - "json_url": "/json", - "db_url": "/db", - "query_url": "/queries?queries=", - "fortune_url": "/fortunes", - "update_url": "/updates?queries=", - "plaintext_url": "/plaintext", - "port": 8080, - "approach": "Realistic", - "classification": "Micro", - "database": "MySQL", - "framework": "sinatra", - "language": "Ruby", - "orm": "Full", - "platform": "Rack", - "webserver": "Passenger", - "os": "Linux", - "database_os": "Linux", - "display_name": "sinatra-passenger-mri", - "versus": "rack-passenger-mri", - "notes": "" - }, "postgres-passenger-mri": { "db_url": "/db", "query_url": "/queries?queries=", @@ -86,28 +64,6 @@ "versus": "rack-postgres-passenger-mri", "notes": "" }, - "unicorn-mri": { - "json_url": "/json", - "db_url": "/db", - "query_url": "/queries?queries=", - "fortune_url": "/fortunes", - "update_url": "/updates?queries=", - "plaintext_url": "/plaintext", - "port": 8080, - "approach": "Realistic", - "classification": "Micro", - "database": "MySQL", - "framework": "sinatra", - "language": "Ruby", - "orm": "Full", - "platform": "Rack", - "webserver": "Unicorn", - "os": "Linux", - "database_os": "Linux", - "display_name": "sinatra-unicorn-mri", - "versus": "rack-unicorn-mri", - "notes": "" - }, "postgres-unicorn-mri": { "db_url": "/db", "query_url": "/queries?queries=", diff --git a/frameworks/Ruby/sinatra/sinatra-passenger-mri.dockerfile b/frameworks/Ruby/sinatra/sinatra-passenger-mri.dockerfile deleted file mode 100644 index eb07d7b5ba7..00000000000 --- a/frameworks/Ruby/sinatra/sinatra-passenger-mri.dockerfile +++ /dev/null @@ -1,26 +0,0 @@ -FROM ruby:3.3 - -ENV RUBY_YJIT_ENABLE=1 - -# Use Jemalloc -RUN apt-get update && \ - apt-get install -y --no-install-recommends libjemalloc2 -ENV LD_PRELOAD=libjemalloc.so.2 - -ADD ./ /sinatra -WORKDIR /sinatra - -RUN bundle install --jobs=4 --gemfile=/sinatra/Gemfile - -# TODO: https://github.com/phusion/passenger/issues/1916 -ENV _PASSENGER_FORCE_HTTP_SESSION=true -ENV DBTYPE=mysql - -RUN ruby -r /sinatra/config/auto_tune -e 'puts auto_tune.first' > instances - -EXPOSE 8080 - -CMD bundle exec passenger start --log-level 1 \ - --engine builtin --disable-turbocaching --disable-security-update-check \ - --spawn-method direct --max-pool-size $(cat instances) --min-instances $(cat instances) --max-request-queue-size 1024 \ - --address 0.0.0.0 --port 8080 --environment production diff --git a/frameworks/Ruby/sinatra/sinatra-unicorn-mri.dockerfile b/frameworks/Ruby/sinatra/sinatra-unicorn-mri.dockerfile deleted file mode 100644 index f0dede838aa..00000000000 --- a/frameworks/Ruby/sinatra/sinatra-unicorn-mri.dockerfile +++ /dev/null @@ -1,19 +0,0 @@ -FROM ruby:3.4-rc - -ENV RUBY_YJIT_ENABLE=1 - -# Use Jemalloc -RUN apt-get update && \ - apt-get install -y --no-install-recommends libjemalloc2 -ENV LD_PRELOAD=libjemalloc.so.2 - -ADD ./ /sinatra -WORKDIR /sinatra - -RUN bundle install --jobs=4 --gemfile=/sinatra/Gemfile - -ENV DBTYPE=mysql - -EXPOSE 8080 - -CMD bundle exec unicorn -c config/mri_unicorn.rb -o 0.0.0.0 -p 8080 -E production From 157bbff3780caa5c2eb5abbeabb7459d7910ae2b Mon Sep 17 00:00:00 2001 From: Petrik de Heus Date: Sun, 27 Oct 2024 17:28:15 +0100 Subject: [PATCH 187/204] [ruby/roda-sequel] Remove some test variations (#9362) Don't run every permutation as there isn't a lot of variation. Limit to running: - Puma with MySQL (the default) - Puma with Postgres - Unicorn with Postgres - Passenger with Postgres This remove the following variations which were slower that their Postgres alternative: - Unicorn with MySQL - Passenger with MySQL --- .../Ruby/roda-sequel/benchmark_config.json | 44 ------------------- .../roda-sequel-passenger-mri.dockerfile | 27 ------------ .../roda-sequel-unicorn-mri.dockerfile | 20 --------- 3 files changed, 91 deletions(-) delete mode 100644 frameworks/Ruby/roda-sequel/roda-sequel-passenger-mri.dockerfile delete mode 100644 frameworks/Ruby/roda-sequel/roda-sequel-unicorn-mri.dockerfile diff --git a/frameworks/Ruby/roda-sequel/benchmark_config.json b/frameworks/Ruby/roda-sequel/benchmark_config.json index 27db92a9b59..2ca8400a156 100644 --- a/frameworks/Ruby/roda-sequel/benchmark_config.json +++ b/frameworks/Ruby/roda-sequel/benchmark_config.json @@ -44,28 +44,6 @@ "versus": "rack-sequel-postgres-puma-mri", "notes": "" }, - "passenger-mri": { - "json_url": "/json", - "db_url": "/db", - "query_url": "/queries?queries=", - "fortune_url": "/fortunes", - "update_url": "/updates?queries=", - "plaintext_url": "/plaintext", - "port": 8080, - "approach": "Realistic", - "classification": "Micro", - "database": "MySQL", - "framework": "roda-sequel", - "language": "Ruby", - "orm": "Full", - "platform": "Rack", - "webserver": "Passenger", - "os": "Linux", - "database_os": "Linux", - "display_name": "roda-sequel-passenger-mri", - "versus": "rack-sequel-passenger-mri", - "notes": "" - }, "postgres-passenger-mri": { "db_url": "/db", "query_url": "/queries?queries=", @@ -86,28 +64,6 @@ "versus": "rack-sequel-postgres-passenger-mri", "notes": "" }, - "unicorn-mri": { - "json_url": "/json", - "db_url": "/db", - "query_url": "/queries?queries=", - "fortune_url": "/fortunes", - "update_url": "/updates?queries=", - "plaintext_url": "/plaintext", - "port": 8080, - "approach": "Realistic", - "classification": "Micro", - "database": "MySQL", - "framework": "roda-sequel", - "language": "Ruby", - "orm": "Full", - "platform": "Rack", - "webserver": "Unicorn", - "os": "Linux", - "database_os": "Linux", - "display_name": "roda-sequel-unicorn-mri", - "versus": "rack-sequel-unicorn-mri", - "notes": "" - }, "postgres-unicorn-mri": { "db_url": "/db", "query_url": "/queries?queries=", diff --git a/frameworks/Ruby/roda-sequel/roda-sequel-passenger-mri.dockerfile b/frameworks/Ruby/roda-sequel/roda-sequel-passenger-mri.dockerfile deleted file mode 100644 index e25f21e20d9..00000000000 --- a/frameworks/Ruby/roda-sequel/roda-sequel-passenger-mri.dockerfile +++ /dev/null @@ -1,27 +0,0 @@ -FROM ruby:3.3 - -ADD ./ /roda-sequel -WORKDIR /roda-sequel - -ENV RUBY_YJIT_ENABLE=1 - -# Use Jemalloc -RUN apt-get update && \ - apt-get install -y --no-install-recommends libjemalloc2 -ENV LD_PRELOAD=libjemalloc.so.2 - -ENV BUNDLE_FORCE_RUBY_PLATFORM=true -RUN bundle install --jobs=8 - -# TODO: https://github.com/phusion/passenger/issues/1916 -ENV _PASSENGER_FORCE_HTTP_SESSION=true -ENV DBTYPE=mysql - -RUN ruby -r /roda-sequel/config/auto_tune -e 'puts auto_tune.first' > instances - -EXPOSE 8080 - -CMD bundle exec passenger start --log-level 1 \ - --engine builtin --disable-turbocaching --disable-security-update-check \ - --spawn-method direct --max-pool-size $(cat instances) --min-instances $(cat instances) --max-request-queue-size 1024 \ - --address 0.0.0.0 --port 8080 --environment production diff --git a/frameworks/Ruby/roda-sequel/roda-sequel-unicorn-mri.dockerfile b/frameworks/Ruby/roda-sequel/roda-sequel-unicorn-mri.dockerfile deleted file mode 100644 index d0cd81077bb..00000000000 --- a/frameworks/Ruby/roda-sequel/roda-sequel-unicorn-mri.dockerfile +++ /dev/null @@ -1,20 +0,0 @@ -FROM ruby:3.4-rc - -ADD ./ /roda-sequel -WORKDIR /roda-sequel - -ENV RUBY_YJIT_ENABLE=1 - -# Use Jemalloc -RUN apt-get update && \ - apt-get install -y --no-install-recommends libjemalloc2 -ENV LD_PRELOAD=libjemalloc.so.2 - -ENV BUNDLE_FORCE_RUBY_PLATFORM=true -RUN bundle install --jobs=8 - -ENV DBTYPE=mysql - -EXPOSE 8080 - -CMD bundle exec unicorn -c config/mri_unicorn.rb -o 0.0.0.0 -p 8080 -E production From 668341f74d7404f998ca65716e1ca1fdc9c085d6 Mon Sep 17 00:00:00 2001 From: Petrik de Heus Date: Sun, 27 Oct 2024 17:28:23 +0100 Subject: [PATCH 188/204] [rails] Test with agoo server (#9363) --- frameworks/Ruby/rails/Gemfile | 29 ++++++++++++++++++--- frameworks/Ruby/rails/Gemfile.lock | 9 +++++++ frameworks/Ruby/rails/benchmark_config.json | 24 +++++++++++++++++ frameworks/Ruby/rails/config/agoo.rb | 0 frameworks/Ruby/rails/rails-agoo.dockerfile | 27 +++++++++++++++++++ 5 files changed, 85 insertions(+), 4 deletions(-) create mode 100644 frameworks/Ruby/rails/config/agoo.rb create mode 100644 frameworks/Ruby/rails/rails-agoo.dockerfile diff --git a/frameworks/Ruby/rails/Gemfile b/frameworks/Ruby/rails/Gemfile index e5d6e743679..b188913327b 100644 --- a/frameworks/Ruby/rails/Gemfile +++ b/frameworks/Ruby/rails/Gemfile @@ -1,10 +1,31 @@ source 'https://rubygems.org' gem 'oj', '~> 3.16' -gem 'pg', '~> 1.5', group: :postgresql -gem 'puma', '~> 6.4', require: false -gem 'falcon', '~> 0.47', require: false gem 'rails', '~> 7.2.0' gem 'redis', '~> 5.0' -gem 'trilogy', '~> 2.8.1', group: :mysql gem 'tzinfo-data' + +group :mysql do + gem 'trilogy', '~> 2.8.1' +end + +group :postgresql do + gem 'pg', '~> 1.5' +end + +group :falcon do + gem 'falcon', '~> 0.47', require: false +end + +group :puma do + gem 'puma', '~> 6.4', require: false +end + +group :unicorn do + gem 'unicorn', '~> 6.1', require: false +end + +group :agoo do + gem 'agoo', require: false + gem 'rackup' +end diff --git a/frameworks/Ruby/rails/Gemfile.lock b/frameworks/Ruby/rails/Gemfile.lock index 311ffc7f814..9773df3e123 100644 --- a/frameworks/Ruby/rails/Gemfile.lock +++ b/frameworks/Ruby/rails/Gemfile.lock @@ -71,6 +71,7 @@ GEM minitest (>= 5.1) securerandom (>= 0.3) tzinfo (~> 2.0, >= 2.0.5) + agoo (2.15.13) async (2.17.0) console (~> 1.26) fiber-annotation @@ -137,6 +138,7 @@ GEM rdoc (>= 4.0.0) reline (>= 0.4.2) json (2.7.2) + kgio (2.11.4) localhost (1.3.1) logger (1.6.1) loofah (2.22.0) @@ -232,6 +234,7 @@ GEM rake (>= 12.2) thor (~> 1.0, >= 1.2.2) zeitwerk (~> 2.6) + raindrops (0.20.1) rake (13.2.1) rdoc (6.7.0) psych (>= 4.0.0) @@ -254,6 +257,9 @@ GEM concurrent-ruby (~> 1.0) tzinfo-data (1.2024.2) tzinfo (>= 1.0.0) + unicorn (6.1.0) + kgio (~> 2.6) + raindrops (~> 0.7) useragent (0.16.10) webrick (1.8.2) websocket-driver (0.7.6) @@ -267,14 +273,17 @@ PLATFORMS x86_64-linux DEPENDENCIES + agoo falcon (~> 0.47) oj (~> 3.16) pg (~> 1.5) puma (~> 6.4) + rackup rails (~> 7.2.0) redis (~> 5.0) trilogy (~> 2.8.1) tzinfo-data + unicorn (~> 6.1) BUNDLED WITH 2.3.3 diff --git a/frameworks/Ruby/rails/benchmark_config.json b/frameworks/Ruby/rails/benchmark_config.json index c5562485d6f..f663c793a3d 100644 --- a/frameworks/Ruby/rails/benchmark_config.json +++ b/frameworks/Ruby/rails/benchmark_config.json @@ -52,6 +52,7 @@ "fortune_url": "/fortunes", "update_url": "/updates?queries=", "plaintext_url": "/plaintext", + "cached_query_url": "/cached?queries=", "port": 8080, "approach": "Realistic", "classification": "Fullstack", @@ -66,6 +67,29 @@ "display_name": "rails-falcon", "notes": "", "versus": "rack-falcon-mri" + }, + "agoo": { + "db_url": "/db", + "json_url": "/json", + "query_url": "/queries?queries=", + "fortune_url": "/fortunes", + "update_url": "/updates?queries=", + "plaintext_url": "/plaintext", + "cached_query_url": "/cached?queries=", + "port": 8080, + "approach": "Realistic", + "classification": "Fullstack", + "database": "Postgres", + "framework": "rails", + "language": "Ruby", + "orm": "Full", + "platform": "Rack", + "webserver": "Agoo", + "os": "Linux", + "database_os": "Linux", + "display_name": "rails-agoo", + "notes": "", + "versus": "" } }] } diff --git a/frameworks/Ruby/rails/config/agoo.rb b/frameworks/Ruby/rails/config/agoo.rb new file mode 100644 index 00000000000..e69de29bb2d diff --git a/frameworks/Ruby/rails/rails-agoo.dockerfile b/frameworks/Ruby/rails/rails-agoo.dockerfile new file mode 100644 index 00000000000..7160fe32f84 --- /dev/null +++ b/frameworks/Ruby/rails/rails-agoo.dockerfile @@ -0,0 +1,27 @@ +FROM ruby:3.4-rc + +RUN apt-get update -yqq && apt-get install -yqq --no-install-recommends redis-server + +EXPOSE 8080 +WORKDIR /rails + +# ENV RUBY_YJIT_ENABLE=1 YJIT is enabled in config/initializers/enable_yjit.rb + +# Use Jemalloc +RUN apt-get update && \ + apt-get install -y --no-install-recommends libjemalloc2 +ENV LD_PRELOAD=libjemalloc.so.2 + +COPY ./Gemfile* /rails/ + +ENV BUNDLE_FORCE_RUBY_PLATFORM=true +ENV BUNDLE_WITHOUT=trilogy +RUN bundle install --jobs=8 + +COPY . /rails/ + +ENV RAILS_ENV=production_postgresql +ENV PORT=8080 +ENV REDIS_URL=redis://localhost:6379/0 +CMD service redis-server start +CMD RACK_ENV=production bundle exec rackup -r agoo -s agoo -p 8080 -q -O workers=$(ruby config/auto_tune.rb | grep -Eo '[0-9]+' | head -n 1) From 961322177427764e65b6a9c2b69757d64e9f71dc Mon Sep 17 00:00:00 2001 From: MARiA so cute <33935209+NathanFreeman@users.noreply.github.com> Date: Mon, 28 Oct 2024 00:28:32 +0800 Subject: [PATCH 189/204] update swoole version to 5.1.5 (#9364) --- frameworks/PHP/swoole/10-opcache.ini | 3 ++- frameworks/PHP/swoole/swoole-async-mysql.dockerfile | 7 +++---- frameworks/PHP/swoole/swoole-async-postgres.dockerfile | 7 +++---- frameworks/PHP/swoole/swoole-server.php | 3 ++- frameworks/PHP/swoole/swoole-sync-mysql.dockerfile | 7 +++---- frameworks/PHP/swoole/swoole-sync-postgres.dockerfile | 7 +++---- 6 files changed, 16 insertions(+), 18 deletions(-) diff --git a/frameworks/PHP/swoole/10-opcache.ini b/frameworks/PHP/swoole/10-opcache.ini index 3e65df6b191..bc77a43761e 100644 --- a/frameworks/PHP/swoole/10-opcache.ini +++ b/frameworks/PHP/swoole/10-opcache.ini @@ -6,4 +6,5 @@ opcache.save_comments=0 opcache.enable_file_override=1 opcache.huge_code_pages=1 opcache.jit_buffer_size=128M -opcache.jit=1225 +mysqlnd.collect_statistics = Off +opcache.jit=tracing diff --git a/frameworks/PHP/swoole/swoole-async-mysql.dockerfile b/frameworks/PHP/swoole/swoole-async-mysql.dockerfile index 9e5e1882565..786f80c88cd 100644 --- a/frameworks/PHP/swoole/swoole-async-mysql.dockerfile +++ b/frameworks/PHP/swoole/swoole-async-mysql.dockerfile @@ -1,6 +1,6 @@ FROM ubuntu:24.04 -ENV SWOOLE_VERSION 5.1.4 +ENV SWOOLE_VERSION 5.1.5 ENV ENABLE_COROUTINE 1 ENV CPU_MULTIPLES 1 ENV DATABASE_DRIVER mysql @@ -16,11 +16,10 @@ RUN apt update -yqq > /dev/null \ && cd /tmp/swoole-src-${SWOOLE_VERSION} \ && phpize > /dev/null \ && ./configure > /dev/null \ - && make -j8 > /dev/null \ + && make -j "$(nproc)" > /dev/null \ && make install > /dev/null \ && echo "extension=swoole.so" > /etc/php/8.3/cli/conf.d/50-swoole.ini \ - && echo "memory_limit=1024M" >> /etc/php/8.3/cli/php.ini \ - && php -m + && echo "memory_limit=1024M" >> /etc/php/8.3/cli/php.ini WORKDIR /swoole diff --git a/frameworks/PHP/swoole/swoole-async-postgres.dockerfile b/frameworks/PHP/swoole/swoole-async-postgres.dockerfile index d431e125b3b..b658f569f0e 100644 --- a/frameworks/PHP/swoole/swoole-async-postgres.dockerfile +++ b/frameworks/PHP/swoole/swoole-async-postgres.dockerfile @@ -1,6 +1,6 @@ FROM ubuntu:24.04 -ENV SWOOLE_VERSION 5.1.4 +ENV SWOOLE_VERSION 5.1.5 ENV ENABLE_COROUTINE 1 ENV CPU_MULTIPLES 1 ENV DATABASE_DRIVER pgsql @@ -16,11 +16,10 @@ RUN apt update -yqq > /dev/null \ && cd /tmp/swoole-src-${SWOOLE_VERSION} \ && phpize > /dev/null \ && ./configure --enable-swoole-pgsql > /dev/null \ - && make -j8 > /dev/null \ + && make -j "$(nproc)" > /dev/null \ && make install > /dev/null \ && echo "extension=swoole.so" > /etc/php/8.3/cli/conf.d/50-swoole.ini \ - && echo "memory_limit=1024M" >> /etc/php/8.3/cli/php.ini \ - && php -m + && echo "memory_limit=1024M" >> /etc/php/8.3/cli/php.ini WORKDIR /swoole diff --git a/frameworks/PHP/swoole/swoole-server.php b/frameworks/PHP/swoole/swoole-server.php index 13050d75ebb..38a4152476f 100644 --- a/frameworks/PHP/swoole/swoole-server.php +++ b/frameworks/PHP/swoole/swoole-server.php @@ -12,7 +12,8 @@ 'worker_num' => swoole_cpu_num() * ((int) getenv('CPU_MULTIPLES')), 'log_file' => '/dev/null', 'enable_coroutine' => $enableCoroutine, - 'enable_reuse_port' => true + 'enable_reuse_port' => true, + 'http_compression' => false ]; if ($enableCoroutine) { diff --git a/frameworks/PHP/swoole/swoole-sync-mysql.dockerfile b/frameworks/PHP/swoole/swoole-sync-mysql.dockerfile index c35d26cdc81..86304d151fc 100644 --- a/frameworks/PHP/swoole/swoole-sync-mysql.dockerfile +++ b/frameworks/PHP/swoole/swoole-sync-mysql.dockerfile @@ -1,6 +1,6 @@ FROM ubuntu:24.04 -ENV SWOOLE_VERSION 5.1.4 +ENV SWOOLE_VERSION 5.1.5 ENV ENABLE_COROUTINE 0 ENV CPU_MULTIPLES 1 ENV DATABASE_DRIVER mysql @@ -16,11 +16,10 @@ RUN apt update -yqq > /dev/null \ && cd /tmp/swoole-src-${SWOOLE_VERSION} \ && phpize > /dev/null \ && ./configure > /dev/null \ - && make -j8 > /dev/null \ + && make -j "$(nproc)" > /dev/null \ && make install > /dev/null \ && echo "extension=swoole.so" > /etc/php/8.3/cli/conf.d/50-swoole.ini \ - && echo "memory_limit=1024M" >> /etc/php/8.3/cli/php.ini \ - && php -m + && echo "memory_limit=1024M" >> /etc/php/8.3/cli/php.ini WORKDIR /swoole diff --git a/frameworks/PHP/swoole/swoole-sync-postgres.dockerfile b/frameworks/PHP/swoole/swoole-sync-postgres.dockerfile index a2661c7c010..8054b66912b 100644 --- a/frameworks/PHP/swoole/swoole-sync-postgres.dockerfile +++ b/frameworks/PHP/swoole/swoole-sync-postgres.dockerfile @@ -1,6 +1,6 @@ FROM ubuntu:24.04 -ENV SWOOLE_VERSION 5.1.4 +ENV SWOOLE_VERSION 5.1.5 ENV ENABLE_COROUTINE 0 ENV CPU_MULTIPLES 4 ENV DATABASE_DRIVER pgsql @@ -16,11 +16,10 @@ RUN apt update -yqq > /dev/null \ && cd /tmp/swoole-src-${SWOOLE_VERSION} \ && phpize > /dev/null \ && ./configure > /dev/null \ - && make -j8 > /dev/null \ + && make -j "$(nproc)" > /dev/null \ && make install > /dev/null \ && echo "extension=swoole.so" > /etc/php/8.3/cli/conf.d/50-swoole.ini \ - && echo "memory_limit=1024M" >> /etc/php/8.3/cli/php.ini \ - && php -m + && echo "memory_limit=1024M" >> /etc/php/8.3/cli/php.ini WORKDIR /swoole From 05ae280b83abd8c11a7b864cd660e89f47044a3c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 28 Oct 2024 18:40:36 +0000 Subject: [PATCH 190/204] Bump rexml from 3.3.6 to 3.3.9 in /frameworks/Ruby/rack Bumps [rexml](https://github.com/ruby/rexml) from 3.3.6 to 3.3.9. - [Release notes](https://github.com/ruby/rexml/releases) - [Changelog](https://github.com/ruby/rexml/blob/master/NEWS.md) - [Commits](https://github.com/ruby/rexml/compare/v3.3.6...v3.3.9) --- updated-dependencies: - dependency-name: rexml dependency-type: indirect ... Signed-off-by: dependabot[bot] --- frameworks/Ruby/rack/Gemfile.lock | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/frameworks/Ruby/rack/Gemfile.lock b/frameworks/Ruby/rack/Gemfile.lock index cf785ab1792..ee579e13085 100644 --- a/frameworks/Ruby/rack/Gemfile.lock +++ b/frameworks/Ruby/rack/Gemfile.lock @@ -86,8 +86,7 @@ GEM rainbow (3.1.1) raindrops (0.20.1) regexp_parser (2.9.2) - rexml (3.3.6) - strscan + rexml (3.3.9) rubocop (1.64.1) json (~> 2.3) language_server-protocol (>= 3.17.0) @@ -110,7 +109,6 @@ GEM sequel_pg (1.17.1) pg (>= 0.18.0, != 1.2.0) sequel (>= 4.38.0) - strscan (3.1.0) traces (0.11.1) tzinfo (2.0.6) concurrent-ruby (~> 1.0) From a65d01af3cf32f9a6d5bcd870ee6de4ba28ca2a6 Mon Sep 17 00:00:00 2001 From: walkor Date: Tue, 5 Nov 2024 02:38:54 +0800 Subject: [PATCH 191/204] [PHP] Add Swoole and Swow as event-driven stress tests for Workerman. (#9382) * Add Swoole and Swow as event-driven stress tests for Workerman. * Text and json requests using Select event-driven --- frameworks/PHP/workerman/Date.php | 15 ++ frameworks/PHP/workerman/Mysql.php | 82 ++++++++++ frameworks/PHP/workerman/MysqlSwoole.php | 91 +++++++++++ frameworks/PHP/workerman/MysqlSwow.php | 12 ++ frameworks/PHP/workerman/Pgsql.php | 65 ++++++++ frameworks/PHP/workerman/PgsqlSwoole.php | 61 ++++++++ frameworks/PHP/workerman/PgsqlSwow.php | 12 ++ frameworks/PHP/workerman/Pool.php | 29 ++++ frameworks/PHP/workerman/app-pg.php | 122 --------------- frameworks/PHP/workerman/app.php | 145 ------------------ .../PHP/workerman/benchmark_config.json | 88 +++++++++++ frameworks/PHP/workerman/composer.json | 5 + frameworks/PHP/workerman/config.toml | 60 ++++++++ frameworks/PHP/workerman/dbraw.php | 88 ----------- frameworks/PHP/workerman/server.php | 97 ++++++++---- .../PHP/workerman/workerman-jit.dockerfile | 1 + .../workerman/workerman-mysql-jit.dockerfile | 1 + .../workerman-mysql-swoole-jit.dockerfile | 34 ++++ .../workerman-mysql-swow-jit.dockerfile | 33 ++++ .../workerman/workerman-pgsql-jit.dockerfile | 1 + .../workerman-pgsql-swoole-jit.dockerfile | 34 ++++ .../workerman-pgsql-swow-jit.dockerfile | 33 ++++ .../PHP/workerman/workerman-pgsql.dockerfile | 1 + frameworks/PHP/workerman/workerman.dockerfile | 1 + 24 files changed, 730 insertions(+), 381 deletions(-) create mode 100644 frameworks/PHP/workerman/Date.php create mode 100644 frameworks/PHP/workerman/Mysql.php create mode 100644 frameworks/PHP/workerman/MysqlSwoole.php create mode 100644 frameworks/PHP/workerman/MysqlSwow.php create mode 100644 frameworks/PHP/workerman/Pgsql.php create mode 100644 frameworks/PHP/workerman/PgsqlSwoole.php create mode 100644 frameworks/PHP/workerman/PgsqlSwow.php create mode 100644 frameworks/PHP/workerman/Pool.php delete mode 100644 frameworks/PHP/workerman/app-pg.php delete mode 100644 frameworks/PHP/workerman/app.php delete mode 100644 frameworks/PHP/workerman/dbraw.php create mode 100644 frameworks/PHP/workerman/workerman-mysql-swoole-jit.dockerfile create mode 100644 frameworks/PHP/workerman/workerman-mysql-swow-jit.dockerfile create mode 100644 frameworks/PHP/workerman/workerman-pgsql-swoole-jit.dockerfile create mode 100644 frameworks/PHP/workerman/workerman-pgsql-swow-jit.dockerfile diff --git a/frameworks/PHP/workerman/Date.php b/frameworks/PHP/workerman/Date.php new file mode 100644 index 00000000000..d09638da713 --- /dev/null +++ b/frameworks/PHP/workerman/Date.php @@ -0,0 +1,15 @@ +date = gmdate('D, d M Y H:i:s').' GMT'; + Timer::add(1, function() { + $this->date = gmdate('D, d M Y H:i:s').' GMT'; + }); + } +} \ No newline at end of file diff --git a/frameworks/PHP/workerman/Mysql.php b/frameworks/PHP/workerman/Mysql.php new file mode 100644 index 00000000000..9c1cdcf0a53 --- /dev/null +++ b/frameworks/PHP/workerman/Mysql.php @@ -0,0 +1,82 @@ +pdo = new PDO( + 'mysql:host=tfb-database;dbname=hello_world', + 'benchmarkdbuser', + 'benchmarkdbpass', + [ + PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, + PDO::ATTR_EMULATE_PREPARES => false + ] + ); + $this->world = $this->pdo->prepare('SELECT id,randomNumber FROM World WHERE id=?'); + $this->fortune = $this->pdo->prepare('SELECT id,message FROM Fortune'); + $this->update = $this->pdo->prepare('UPDATE World SET randomNumber=? WHERE id=?'); + } + + function db(): array + { + $this->world->execute([mt_rand(1, 10000)]); + return $this->world->fetch(); + } + + function query($request): array + { + $query_count = 1; + $q = (int)$request->get('q'); + if ($q > 1) { + $query_count = min($q, 500); + } + $arr = []; + while ($query_count--) { + $this->world->execute([mt_rand(1, 10000)]); + $arr[] = $this->world->fetch(); + } + return $arr; + } + + function update($request): array + { + $query_count = 1; + $q = (int)$request->get('q'); + if ($q > 1) { + $query_count = min($q, 500); + } + $arr = []; + while ($query_count--) { + $id = mt_rand(1, 10000); + $this->world->execute([$id]); + $item = $this->world->fetch(); + $this->update->execute( + [$item['randomNumber'] = mt_rand(1, 10000), $id] + ); + $arr[] = $item; + } + return $arr; + } + + function fortune(): string + { + $this->fortune->execute(); + $arr = $this->fortune->fetchAll(PDO::FETCH_KEY_PAIR); + $arr[0] = 'Additional fortune added at request time.'; + asort($arr); + $html = ''; + foreach ($arr as $id => $message) { + $message = htmlspecialchars($message, ENT_QUOTES, 'UTF-8'); + $html .= "$id$message"; + } + return "Fortunes$html
    idmessage
    "; + } + +} \ No newline at end of file diff --git a/frameworks/PHP/workerman/MysqlSwoole.php b/frameworks/PHP/workerman/MysqlSwoole.php new file mode 100644 index 00000000000..ff290648fa1 --- /dev/null +++ b/frameworks/PHP/workerman/MysqlSwoole.php @@ -0,0 +1,91 @@ +withDriver('mysql') + ->withHost('tfb-database') + ->withPort(3306) + ->withDbName('hello_world') + ->withUsername('benchmarkdbuser') + ->withPassword('benchmarkdbpass'); + $this->pool = new PDOPool($config, $size); + } + + function db(): array + { + $pdo = $this->pool->get(); + $stmt = $pdo->prepare('SELECT id,randomNumber FROM World WHERE id=?'); + $stmt->execute([mt_rand(1, 10000)]); + $result = $stmt->fetch(PDO::FETCH_ASSOC); + $this->pool->put($pdo); + return $result; + } + + function query($request): array + { + $query_count = 1; + $q = (int)$request->get('q'); + if ($q > 1) { + $query_count = min($q, 500); + } + $pdo = $this->pool->get(); + $stmt = $pdo->prepare('SELECT id,randomNumber FROM World WHERE id=?'); + $arr = []; + while ($query_count--) { + $stmt->execute([mt_rand(1, 10000)]); + $arr[] = $stmt->fetch(PDO::FETCH_ASSOC); + } + $this->pool->put($pdo); + return $arr; + } + + function update($request): array + { + $query_count = 1; + $q = (int)$request->get('q'); + if ($q > 1) { + $query_count = min($q, 500); + } + $arr = []; + $pdo = $this->pool->get(); + $world = $pdo->prepare('SELECT id,randomNumber FROM World WHERE id=?'); + $update = $pdo->prepare('UPDATE World SET randomNumber=? WHERE id=?'); + while ($query_count--) { + $id = mt_rand(1, 10000); + $world->execute([$id]); + $item = $world->fetch(PDO::FETCH_ASSOC); + $update->execute( + [$item['randomNumber'] = mt_rand(1, 10000), $id] + ); + $arr[] = $item; + } + $this->pool->put($pdo); + return $arr; + } + + function fortune(): string + { + $pdo = $this->pool->get(); + $stmt = $pdo->prepare('SELECT id,message FROM Fortune'); + $stmt->execute(); + $arr = $stmt->fetchAll(PDO::FETCH_KEY_PAIR); + $this->pool->put($pdo); + $arr[0] = 'Additional fortune added at request time.'; + asort($arr); + $html = ''; + foreach ($arr as $id => $message) { + $message = htmlspecialchars($message, ENT_QUOTES, 'UTF-8'); + $html .= "$id$message"; + } + return "Fortunes$html
    idmessage
    "; + } + +} \ No newline at end of file diff --git a/frameworks/PHP/workerman/MysqlSwow.php b/frameworks/PHP/workerman/MysqlSwow.php new file mode 100644 index 00000000000..81cb8534c2a --- /dev/null +++ b/frameworks/PHP/workerman/MysqlSwow.php @@ -0,0 +1,12 @@ +pool = new Pool("mysql:host=tfb-database;dbname=hello_world", 'benchmarkdbuser', 'benchmarkdbpass', $size); + } + +} \ No newline at end of file diff --git a/frameworks/PHP/workerman/Pgsql.php b/frameworks/PHP/workerman/Pgsql.php new file mode 100644 index 00000000000..f86dc6364af --- /dev/null +++ b/frameworks/PHP/workerman/Pgsql.php @@ -0,0 +1,65 @@ +pdo = new PDO( + 'pgsql:host=tfb-database;dbname=hello_world', + 'benchmarkdbuser', + 'benchmarkdbpass', + [ + PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, + PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, + PDO::ATTR_EMULATE_PREPARES => false + ] + ); + $this->world = $this->random = $this->pdo->prepare('SELECT id,randomNumber FROM World WHERE id=?'); + $this->fortune = $this->pdo->prepare('SELECT id,message FROM Fortune'); + $this->update = $this->pdo->prepare('UPDATE World SET randomNumber=? WHERE id=?'); + } + + function update($request): array + { + $query_count = 1; + $q = (int)$request->get('q'); + if ($q > 1) { + $query_count = min($q, 500); + } + $worlds = []; + while ($query_count--) { + $this->random->execute([\mt_rand(1, 10000)]); + $world = $this->random->fetch(); + $world['randomNumber'] = \mt_rand(1, 10000); + $worlds[] = $world; + } + $rows = count($worlds); + + if (!isset($this->updates[$rows])) { + $sql = 'UPDATE world SET randomNumber = CASE id' + . str_repeat(' WHEN ?::INTEGER THEN ?::INTEGER ', $rows) + . 'END WHERE id IN (' + . str_repeat('?::INTEGER,', $rows - 1) . '?::INTEGER)'; + + $this->updates[$rows] = $this->pdo->prepare($sql); + } + + $val = []; + $keys = []; + foreach ($worlds as $world) { + $val[] = $keys[] = $world['id']; + $val[] = $world['randomNumber']; + } + + $this->updates[$rows]->execute([...$val, ...$keys]); + return $worlds; + } + +} \ No newline at end of file diff --git a/frameworks/PHP/workerman/PgsqlSwoole.php b/frameworks/PHP/workerman/PgsqlSwoole.php new file mode 100644 index 00000000000..1a999aac982 --- /dev/null +++ b/frameworks/PHP/workerman/PgsqlSwoole.php @@ -0,0 +1,61 @@ +withDriver('pgsql') + ->withHost('tfb-database') + ->withPort(5432) + ->withDbName('hello_world') + ->withUsername('benchmarkdbuser') + ->withPassword('benchmarkdbpass'); + + $this->pool = new PDOPool($config, $size); + } + + + function update($request): array + { + $query_count = 1; + $q = (int)$request->get('q'); + if ($q > 1) { + $query_count = min($q, 500); + } + $worlds = []; + $pdo = $this->pool->get(); + $random = $pdo->prepare('SELECT id,randomNumber FROM World WHERE id=?'); + while ($query_count--) { + $random->execute([mt_rand(1, 10000)]); + $world = $random->fetch(PDO::FETCH_ASSOC); + $world['randomNumber'] = mt_rand(1, 10000); + $worlds[] = $world; + } + $rows = count($worlds); + + $sql = 'UPDATE world SET randomNumber = CASE id' + . str_repeat(' WHEN ?::INTEGER THEN ?::INTEGER ', $rows) + . 'END WHERE id IN (' + . str_repeat('?::INTEGER,', $rows - 1) . '?::INTEGER)'; + + $update = $pdo->prepare($sql); + + $val = []; + $keys = []; + foreach ($worlds as $world) { + $val[] = $keys[] = $world['id']; + $val[] = $world['randomNumber']; + } + + $update->execute([...$val, ...$keys]); + $this->pool->put($pdo); + return $worlds; + } + +} \ No newline at end of file diff --git a/frameworks/PHP/workerman/PgsqlSwow.php b/frameworks/PHP/workerman/PgsqlSwow.php new file mode 100644 index 00000000000..c2a2d3cc4aa --- /dev/null +++ b/frameworks/PHP/workerman/PgsqlSwow.php @@ -0,0 +1,12 @@ +pool = new Pool("pgsql:host=tfb-database;dbname=hello_world", 'benchmarkdbuser', 'benchmarkdbpass', $size); + } + +} \ No newline at end of file diff --git a/frameworks/PHP/workerman/Pool.php b/frameworks/PHP/workerman/Pool.php new file mode 100644 index 00000000000..522ad7afed2 --- /dev/null +++ b/frameworks/PHP/workerman/Pool.php @@ -0,0 +1,29 @@ +push(new PDO($dsn, $username, $password,[ + PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC + ])); + } + } + + public function get(): PDO + { + return static::$channel->pop(); + } + + public function put(PDO $pdo) + { + return static::$channel->push($pdo); + } +} \ No newline at end of file diff --git a/frameworks/PHP/workerman/app-pg.php b/frameworks/PHP/workerman/app-pg.php deleted file mode 100644 index b92809d2787..00000000000 --- a/frameworks/PHP/workerman/app-pg.php +++ /dev/null @@ -1,122 +0,0 @@ -path()) { - '/plaintext' => text(), - '/json' => json(), - '/db' => db(), - '/fortunes' => fortune(), - '/query' => query($request), - '/update' => updateraw($request), - // '/info' => info(), - default => new Response(404, [], 'Error 404'), - }; -} - -function text() -{ - return new Response(200, [ - 'Content-Type' => 'text/plain', - 'Date' => Header::$date - ], 'Hello, World!'); -} - -function json() -{ - return new Response(200, [ - 'Content-Type' => 'application/json', - 'Date' => Header::$date - ], json_encode(['message' => 'Hello, World!'])); -} - -function db() -{ - DbRaw::$random->execute([mt_rand(1, 10000)]); - - return new Response(200, [ - 'Content-Type' => 'application/json', - 'Date' => Header::$date - ], json_encode(DbRaw::$random->fetch())); -} - -function query($request) -{ - $random = DbRaw::$random; - - $query_count = 1; - $q = (int) $request->get('q'); - if ($q > 1) { - $query_count = min($q, 500); - } - - while ($query_count--) { - $random->execute([mt_rand(1, 10000)]); - $arr[] = $random->fetch(); - } - - return new Response(200, [ - 'Content-Type' => 'application/json', - 'Date' => Header::$date - ], json_encode($arr)); -} - -function updateraw($request) -{ - $random = DbRaw::$random; - - $query_count = 1; - $q = (int) $request->get('q'); - if ($q > 1) { - $query_count = min($q, 500); - } - - while ($query_count--) { - - $random->execute([mt_rand(1, 10000)]); - $row = $random->fetch(); - $row['randomNumber'] = mt_rand(1, 10000); - - $worlds[] = $row; - } - - DbRaw::update($worlds); - - return new Response(200, [ - 'Content-Type' => 'application/json', - 'Date' => Header::$date - ], json_encode($worlds)); -} - -function fortune() -{ - DbRaw::$fortune->execute(); - - $arr = DbRaw::$fortune->fetchAll(PDO::FETCH_KEY_PAIR); - $arr[0] = 'Additional fortune added at request time.'; - asort($arr); - - $html = ''; - foreach ($arr as $id => $message) { - $message = htmlspecialchars($message, ENT_QUOTES, 'UTF-8'); - $html .= "$id$message"; - } - - return new Response(200, [ - 'Date' => Header::$date - ], "Fortunes$html
    idmessage
    " - ); -} - -/* function info() -{ - ob_start(); - phpinfo(); - return new Response(200, ['Content-Type' => 'text/plain'], ob_get_clean()); -} - */ diff --git a/frameworks/PHP/workerman/app.php b/frameworks/PHP/workerman/app.php deleted file mode 100644 index ad6b7997efc..00000000000 --- a/frameworks/PHP/workerman/app.php +++ /dev/null @@ -1,145 +0,0 @@ - PDO::FETCH_ASSOC, - PDO::ATTR_EMULATE_PREPARES => false - ] - ); - $world = $pdo->prepare('SELECT id,randomNumber FROM World WHERE id=?'); - $fortune = $pdo->prepare('SELECT id,message FROM Fortune'); - $update = $pdo->prepare('UPDATE World SET randomNumber=? WHERE id=?'); -} - -function router(Request $request) -{ - return match($request->path()) { - '/plaintext' => text(), - '/json' => json(), - '/db' => db(), - '/fortunes' => fortune(), - '/query' => query($request), - '/update' => updateraw($request), - // '/info' => info(), - default => new Response(404, [], 'Error 404'), - }; -} - -function text() -{ - return new Response(200, [ - 'Content-Type' => 'text/plain', - 'Date' => Header::$date - ], 'Hello, World!'); -} - -function json() -{ - return new Response(200, [ - 'Content-Type' => 'application/json', - 'Date' => Header::$date - ], json_encode(['message' => 'Hello, World!'])); -} - -function db() -{ - global $world; - - $world->execute([mt_rand(1, 10000)]); - - return new Response(200, [ - 'Content-Type' => 'application/json', - 'Date' => Header::$date - ], json_encode($world->fetch())); -} - -function query($request) -{ - global $world; - - $query_count = 1; - $q = (int) $request->get('q'); - if ($q > 1) { - $query_count = min($q, 500); - } - - while ($query_count--) { - $world->execute([mt_rand(1, 10000)]); - $arr[] = $world->fetch(); - } - - return new Response(200, [ - 'Content-Type' => 'application/json', - 'Date' => Header::$date - ], json_encode($arr)); -} - -function updateraw($request) -{ - global $world, $update; - - $query_count = 1; - $q = (int) $request->get('q'); - if ($q > 1) { - $query_count = min($q, 500); - } - - while ($query_count--) { - $id = mt_rand(1, 10000); - $world->execute([$id]); - $item = $world->fetch(); - $update->execute( - [$item['randomNumber'] = mt_rand(1, 10000), $id] - ); - - $arr[] = $item; - } - - // $pdo->beginTransaction(); - // foreach($arr as $world) { - // $update->execute([$world['randomNumber'], $world['id']]); - // } - // $pdo->commit(); - return new Response(200, [ - 'Content-Type' => 'application/json', - 'Date' => Header::$date - ], json_encode($arr)); -} - -function fortune() -{ - global $fortune; - - $fortune->execute(); - - $arr = $fortune->fetchAll(PDO::FETCH_KEY_PAIR); - $arr[0] = 'Additional fortune added at request time.'; - asort($arr); - - $html = ''; - foreach ($arr as $id => $message) { - $message = htmlspecialchars($message, ENT_QUOTES, 'UTF-8'); - $html .= "$id$message"; - } - - return new Response(200, [ - 'Date' => Header::$date - ], "Fortunes$html
    idmessage
    " - ); -} - -/* function info() -{ - ob_start(); - phpinfo(); - return new Response(200, ['Content-Type' => 'text/plain'], ob_get_clean()); -} - */ \ No newline at end of file diff --git a/frameworks/PHP/workerman/benchmark_config.json b/frameworks/PHP/workerman/benchmark_config.json index bcb286db6d8..a2077767b43 100644 --- a/frameworks/PHP/workerman/benchmark_config.json +++ b/frameworks/PHP/workerman/benchmark_config.json @@ -107,6 +107,94 @@ "display_name": "workerman [pgsql]", "notes": "", "versus": "php" + }, + "pgsql-swow": { + "dockerfile": "workerman-pgsql-swow-jit.dockerfile", + "db_url": "/db", + "query_url": "/query?q=", + "update_url": "/update?q=", + "fortune_url": "/fortunes", + "port": 8080, + "approach": "Realistic", + "classification": "Platform", + "database": "Postgres", + "framework": "workerman", + "language": "PHP", + "flavor": "PHP8", + "orm": "Raw", + "platform": "workerman", + "webserver": "None", + "os": "Linux", + "database_os": "Linux", + "display_name": "workerman [jit, pgsql, swow, async]", + "notes": "", + "versus": "php" + }, + "mysql-swow": { + "dockerfile": "workerman-mysql-swow-jit.dockerfile", + "db_url": "/db", + "query_url": "/query?q=", + "update_url": "/update?q=", + "fortune_url": "/fortunes", + "port": 8080, + "approach": "Realistic", + "classification": "Platform", + "database": "MySQL", + "framework": "workerman", + "language": "PHP", + "flavor": "PHP8", + "orm": "Raw", + "platform": "workerman", + "webserver": "None", + "os": "Linux", + "database_os": "Linux", + "display_name": "workerman [jit, mysql, swow, async]", + "notes": "", + "versus": "php" + }, + "pgsql-swoole": { + "dockerfile": "workerman-pgsql-swoole-jit.dockerfile", + "db_url": "/db", + "query_url": "/query?q=", + "update_url": "/update?q=", + "fortune_url": "/fortunes", + "port": 8080, + "approach": "Realistic", + "classification": "Platform", + "database": "Postgres", + "framework": "workerman", + "language": "PHP", + "flavor": "PHP8", + "orm": "Raw", + "platform": "workerman", + "webserver": "None", + "os": "Linux", + "database_os": "Linux", + "display_name": "workerman [jit, pgsql, swoole, async]", + "notes": "", + "versus": "php" + }, + "mysql-swoole": { + "dockerfile": "workerman-mysql-swoole-jit.dockerfile", + "db_url": "/db", + "query_url": "/query?q=", + "update_url": "/update?q=", + "fortune_url": "/fortunes", + "port": 8080, + "approach": "Realistic", + "classification": "Platform", + "database": "MySQL", + "framework": "workerman", + "language": "PHP", + "flavor": "PHP8", + "orm": "Raw", + "platform": "workerman", + "webserver": "None", + "os": "Linux", + "database_os": "Linux", + "display_name": "workerman [jit, mysql, swoole, async]", + "notes": "", + "versus": "php" } }] } diff --git a/frameworks/PHP/workerman/composer.json b/frameworks/PHP/workerman/composer.json index 7e6c8b1f088..d0c8ca7e678 100644 --- a/frameworks/PHP/workerman/composer.json +++ b/frameworks/PHP/workerman/composer.json @@ -1,5 +1,10 @@ { "require": { "workerman/workerman": "dev-master" + }, + "autoload": { + "psr-4": { + "": "./" + } } } diff --git a/frameworks/PHP/workerman/config.toml b/frameworks/PHP/workerman/config.toml index b2f50bda1a0..791e9502688 100644 --- a/frameworks/PHP/workerman/config.toml +++ b/frameworks/PHP/workerman/config.toml @@ -82,4 +82,64 @@ os = "Linux" orm = "Raw" platform = "workerman" webserver = "None" +versus = "php" + +[pgsql-swow] +urls.db = "/db" +urls.query = "/query?q=" +urls.update = "/update?q=" +urls.fortune = "/fortunes" +approach = "Realistic" +classification = "Platform" +database = "Postgres" +database_os = "Linux" +os = "Linux" +orm = "Raw" +platform = "workerman" +webserver = "None" +versus = "php" + +[mysql-swow] +urls.db = "/db" +urls.query = "/query?q=" +urls.update = "/update?q=" +urls.fortune = "/fortunes" +approach = "Realistic" +classification = "Platform" +database = "MySQL" +database_os = "Linux" +os = "Linux" +orm = "Raw" +platform = "workerman" +webserver = "None" +versus = "php" + +[pgsql-swoole] +urls.db = "/db" +urls.query = "/query?q=" +urls.update = "/update?q=" +urls.fortune = "/fortunes" +approach = "Realistic" +classification = "Platform" +database = "Postgres" +database_os = "Linux" +os = "Linux" +orm = "Raw" +platform = "workerman" +webserver = "None" +versus = "php" + +[mysql-swoole] +urls.db = "/db" +urls.query = "/query?q=" +urls.update = "/update?q=" +urls.fortune = "/fortunes" +approach = "Realistic" +classification = "Platform" +database = "MySQL" +database_os = "Linux" +os = "Linux" +orm = "Raw" +platform = "workerman" +webserver = "None" versus = "php" \ No newline at end of file diff --git a/frameworks/PHP/workerman/dbraw.php b/frameworks/PHP/workerman/dbraw.php deleted file mode 100644 index 2a7c8d355c1..00000000000 --- a/frameworks/PHP/workerman/dbraw.php +++ /dev/null @@ -1,88 +0,0 @@ - PDO::FETCH_ASSOC, - PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, - PDO::ATTR_EMULATE_PREPARES => false - ] - ); - - self::$fortune = $pdo->prepare('SELECT id,message FROM Fortune'); - self::$random = $pdo->prepare('SELECT id,randomNumber FROM World WHERE id = ?'); - self::$instance = $pdo; - } - - /** - * Postgres bulk update - * - * @param array $worlds - * @return void - */ - public static function update(array $worlds) - { - $rows = count($worlds); - - if (!isset(self::$update[$rows])) { - $sql = 'UPDATE world SET randomNumber = CASE id' - . str_repeat(' WHEN ?::INTEGER THEN ?::INTEGER ', $rows) - . 'END WHERE id IN (' - . str_repeat('?::INTEGER,', $rows - 1) . '?::INTEGER)'; - - self::$update[$rows] = self::$instance->prepare($sql); - } - - $val = []; - $keys = []; - foreach ($worlds as $world) { - $val[] = $keys[] = $world['id']; - $val[] = $world['randomNumber']; - } - - self::$update[$rows]->execute([...$val, ...$keys]); - } - - /** - * Alternative bulk update in Postgres - * - * @param array $worlds - * @return void - */ - public static function update2(array $worlds) - { - $rows = count($worlds); - - if (!isset(self::$update[$rows])) { - $sql = 'UPDATE world SET randomNumber = temp.randomNumber FROM (VALUES ' - . implode(', ', array_fill(0, $rows, '(?::INTEGER, ?::INTEGER)')) . - ' ORDER BY 1) AS temp(id, randomNumber) WHERE temp.id = world.id'; - - self::$update[$rows] = self::$instance->prepare($sql); - } - - $val = []; - foreach ($worlds as $world) { - $val[] = $world['id']; - $val[] = $world['randomNumber']; - //$update->bindParam(++$i, $world['id'], PDO::PARAM_INT); - } - - self::$update[$rows]->execute($val); - } -} diff --git a/frameworks/PHP/workerman/server.php b/frameworks/PHP/workerman/server.php index f856790efa9..a8499e4f538 100644 --- a/frameworks/PHP/workerman/server.php +++ b/frameworks/PHP/workerman/server.php @@ -2,37 +2,82 @@ require_once __DIR__.'/vendor/autoload.php'; use Workerman\Worker; -use Workerman\Timer; +use Workerman\Events\Swow; +use Workerman\Events\Swoole; +use Workerman\Events\Select; +use Workerman\Protocols\Http\Response; $test_type = getenv('TEST_TYPE') ?: 'default'; -if ($test_type === 'pgsql') { - require_once __DIR__.'/app-pg.php'; -} else { - require_once __DIR__.'/app.php'; -} -$process_count = (int) shell_exec('nproc') * ($test_type === 'default' ? 1 : 4); +$process = getenv('PROCESS_MULTIPLIER') ?: 1; +$pool_size = getenv('POOL_SIZE') ?: 2; +$process_count = (int) shell_exec('nproc') * $process; -$http_worker = new Worker('http://0.0.0.0:8080'); -$http_worker->reusePort = true; -$http_worker->count = $process_count; -$http_worker->onWorkerStart = static function () use ($test_type) { - Header::$date = gmdate('D, d M Y H:i:s').' GMT'; - Timer::add(1, function() { - Header::$date = gmdate('D, d M Y H:i:s').' GMT'; - }); - if ($test_type === 'pgsql') { - DbRaw::init(); - } else { - init(); - } +$db = $date = null; +$http_worker = new Worker('http://0.0.0.0:8080'); +//$http_worker->reusePort = true; +$http_worker->count = $process_count; +$http_worker->onWorkerStart = static function () use ($test_type, $pool_size, &$db, &$date) { + $db = match ($test_type) { + 'pgsql' => new Pgsql(), + 'mysql' => new Mysql(), + 'pgsql-swow' => new PgsqlSwow($pool_size), + 'mysql-swow' => new MysqlSwow($pool_size), + 'pgsql-swoole' => new PgsqlSwoole($pool_size), + 'mysql-swoole' => new MysqlSwoole($pool_size), + 'default' => new Mysql(), + }; + $date = new Date(); }; +if ($test_type === 'default') { + Worker::$eventLoopClass = Select::class; +} elseif (in_array($test_type, ['pgsql-swow', 'mysql-swow'])) { + Worker::$eventLoopClass = Swow::class; +} elseif (in_array($test_type, ['pgsql-swoole', 'mysql-swoole'])) { + Worker::$eventLoopClass = Swoole::class; +} -$http_worker->onMessage = static function ($connection, $request) { - $connection->send(router($request)); +$http_worker->onMessage = static function ($connection, $request) use (&$db, &$date) { + switch ($request->path()) { + case '/plaintext': + $connection->headers = [ + 'Content-Type' => 'text/plain', + 'Date' => $date->date + ]; + return $connection->send('Hello, World!'); + case '/json': + $connection->headers = [ + 'Content-Type' => 'application/json', + 'Date' => $date->date + ]; + return $connection->send(json_encode(['message' => 'Hello, World!'])); + case '/db': + $connection->headers = [ + 'Content-Type' => 'application/json', + 'Date' => $date->date + ]; + return $connection->send(json_encode($db->db())); + case '/fortunes': + $connection->headers = [ + 'Date' => $date->date + ]; + return $connection->send($db->fortune()); + case '/query': + $connection->headers = [ + 'Content-Type' => 'application/json', + 'Date' => $date->date + ]; + return $connection->send(json_encode($db->query($request))); + case '/update': + $connection->headers = [ + 'Content-Type' => 'application/json', + 'Date' => $date->date + ]; + return $connection->send(json_encode($db->update($request))); + } + return $connection->send(new Response(404, [ + 'Content-Type' => 'text/plain', + 'Date' => $date->date + ], '404 Not Found')); }; Worker::runAll(); - -class Header { - public static $date = null; -} diff --git a/frameworks/PHP/workerman/workerman-jit.dockerfile b/frameworks/PHP/workerman/workerman-jit.dockerfile index c90794ab9be..6ff432c60b8 100644 --- a/frameworks/PHP/workerman/workerman-jit.dockerfile +++ b/frameworks/PHP/workerman/workerman-jit.dockerfile @@ -1,6 +1,7 @@ FROM ubuntu:24.04 ENV TEST_TYPE default +ENV PROCESS_MULTIPLIER 1 ARG DEBIAN_FRONTEND=noninteractive diff --git a/frameworks/PHP/workerman/workerman-mysql-jit.dockerfile b/frameworks/PHP/workerman/workerman-mysql-jit.dockerfile index 7d8fd9e238d..33ad3879954 100644 --- a/frameworks/PHP/workerman/workerman-mysql-jit.dockerfile +++ b/frameworks/PHP/workerman/workerman-mysql-jit.dockerfile @@ -1,6 +1,7 @@ FROM ubuntu:24.04 ENV TEST_TYPE mysql +ENV PROCESS_MULTIPLIER 4 ARG DEBIAN_FRONTEND=noninteractive diff --git a/frameworks/PHP/workerman/workerman-mysql-swoole-jit.dockerfile b/frameworks/PHP/workerman/workerman-mysql-swoole-jit.dockerfile new file mode 100644 index 00000000000..eb88aae9c88 --- /dev/null +++ b/frameworks/PHP/workerman/workerman-mysql-swoole-jit.dockerfile @@ -0,0 +1,34 @@ +FROM ubuntu:24.04 + +ENV TEST_TYPE mysql-swoole +ENV SWOOLE_VERSION 5.1.5 +ENV PROCESS_MULTIPLIER 1 +ENV POOL_SIZE 4 + +ARG DEBIAN_FRONTEND=noninteractive + +RUN apt update -yqq > /dev/null \ + && apt install -yqq software-properties-common > /dev/null \ + && LC_ALL=C.UTF-8 add-apt-repository ppa:ondrej/php > /dev/null \ + && apt update -yqq > /dev/null \ + && apt install libbrotli-dev php8.3-cli php8.3-pdo-mysql php8.3-dev php8.3-mbstring git -y > /dev/null \ + && cd /tmp && curl -sSL "https://github.com/swoole/swoole-src/archive/v${SWOOLE_VERSION}.tar.gz" | tar xzf - \ + && cd /tmp/swoole-src-${SWOOLE_VERSION} \ + && phpize > /dev/null \ + && ./configure > /dev/null \ + && make -j "$(nproc)" > /dev/null \ + && make install > /dev/null \ + && echo "extension=swoole.so" > /etc/php/8.3/cli/conf.d/50-swoole.ini \ + && echo "memory_limit=1024M" >> /etc/php/8.3/cli/php.ini + +COPY --from=composer/composer:latest-bin --link /composer /usr/local/bin/composer + +WORKDIR /workerman +COPY --link . . + +RUN composer install --optimize-autoloader --classmap-authoritative --no-dev --quiet +COPY php-jit.ini /etc/php/8.3/cli/conf.d/10-opcache.ini + +EXPOSE 8080 + +CMD php /workerman/server.php start diff --git a/frameworks/PHP/workerman/workerman-mysql-swow-jit.dockerfile b/frameworks/PHP/workerman/workerman-mysql-swow-jit.dockerfile new file mode 100644 index 00000000000..2e3e571dbce --- /dev/null +++ b/frameworks/PHP/workerman/workerman-mysql-swow-jit.dockerfile @@ -0,0 +1,33 @@ +FROM ubuntu:24.04 + +ENV TEST_TYPE mysql-swow +ENV PROCESS_MULTIPLIER 1 +ENV POOL_SIZE 4 + +ARG DEBIAN_FRONTEND=noninteractive + +RUN apt-get update -yqq && apt-get install -yqq software-properties-common > /dev/null +RUN LC_ALL=C.UTF-8 add-apt-repository ppa:ondrej/php > /dev/null && \ + apt-get update -yqq > /dev/null && apt-get upgrade -yqq > /dev/null + +RUN apt-get install -yqq php8.3-cli php8.3-mysql php8.3-xml > /dev/null + +COPY --from=composer/composer:latest-bin --link /composer /usr/local/bin/composer + +RUN apt-get install -y php-pear php8.3-dev git > /dev/null + + +WORKDIR /workerman +COPY --link . . + + +RUN composer require swow/swow > /dev/null +RUN ./vendor/bin/swow-builder --install > /dev/null +RUN echo extension=swow.so > /etc/php/8.3/cli/conf.d/20-swow.ini +RUN composer install --optimize-autoloader --classmap-authoritative --no-dev --quiet +COPY php-jit.ini /etc/php/8.3/cli/conf.d/10-opcache.ini + +EXPOSE 8080 + + +CMD php /workerman/server.php start diff --git a/frameworks/PHP/workerman/workerman-pgsql-jit.dockerfile b/frameworks/PHP/workerman/workerman-pgsql-jit.dockerfile index 6c4af626cc0..dcd2ce482e9 100644 --- a/frameworks/PHP/workerman/workerman-pgsql-jit.dockerfile +++ b/frameworks/PHP/workerman/workerman-pgsql-jit.dockerfile @@ -1,6 +1,7 @@ FROM ubuntu:24.04 ENV TEST_TYPE pgsql +ENV PROCESS_MULTIPLIER 4 ARG DEBIAN_FRONTEND=noninteractive diff --git a/frameworks/PHP/workerman/workerman-pgsql-swoole-jit.dockerfile b/frameworks/PHP/workerman/workerman-pgsql-swoole-jit.dockerfile new file mode 100644 index 00000000000..fbc563d68f9 --- /dev/null +++ b/frameworks/PHP/workerman/workerman-pgsql-swoole-jit.dockerfile @@ -0,0 +1,34 @@ +FROM ubuntu:24.04 + +ENV TEST_TYPE pgsql-swoole +ENV SWOOLE_VERSION 5.1.5 +ENV PROCESS_MULTIPLIER 2 +ENV POOL_SIZE 16 + +ARG DEBIAN_FRONTEND=noninteractive + +RUN apt update -yqq > /dev/null \ + && apt install -yqq software-properties-common > /dev/null \ + && LC_ALL=C.UTF-8 add-apt-repository ppa:ondrej/php > /dev/null \ + && apt update -yqq > /dev/null \ + && apt install libbrotli-dev php8.3-cli php8.3-pdo-pgsql php8.3-dev libpq-dev php8.3-mbstring git -y > /dev/null \ + && cd /tmp && curl -sSL "https://github.com/swoole/swoole-src/archive/v${SWOOLE_VERSION}.tar.gz" | tar xzf - \ + && cd /tmp/swoole-src-${SWOOLE_VERSION} \ + && phpize > /dev/null \ + && ./configure --enable-swoole-pgsql > /dev/null \ + && make -j "$(nproc)" > /dev/null \ + && make install > /dev/null \ + && echo "extension=swoole.so" > /etc/php/8.3/cli/conf.d/50-swoole.ini \ + && echo "memory_limit=1024M" >> /etc/php/8.3/cli/php.ini + +COPY --from=composer/composer:latest-bin --link /composer /usr/local/bin/composer + +WORKDIR /workerman +COPY --link . . + +RUN composer install --optimize-autoloader --classmap-authoritative --no-dev --quiet +COPY php-jit.ini /etc/php/8.3/cli/conf.d/10-opcache.ini + +EXPOSE 8080 + +CMD php /workerman/server.php start diff --git a/frameworks/PHP/workerman/workerman-pgsql-swow-jit.dockerfile b/frameworks/PHP/workerman/workerman-pgsql-swow-jit.dockerfile new file mode 100644 index 00000000000..d58d7b4865d --- /dev/null +++ b/frameworks/PHP/workerman/workerman-pgsql-swow-jit.dockerfile @@ -0,0 +1,33 @@ +FROM ubuntu:24.04 + +ENV TEST_TYPE pgsql-swow +ENV PROCESS_MULTIPLIER 2 +ENV POOL_SIZE 16 + +ARG DEBIAN_FRONTEND=noninteractive + +RUN apt-get update -yqq && apt-get install -yqq software-properties-common > /dev/null +RUN LC_ALL=C.UTF-8 add-apt-repository ppa:ondrej/php > /dev/null && \ + apt-get update -yqq > /dev/null && apt-get upgrade -yqq > /dev/null + +RUN apt-get install -yqq php8.3-cli php8.3-pgsql php8.3-xml > /dev/null + +COPY --from=composer/composer:latest-bin --link /composer /usr/local/bin/composer + +RUN apt-get install -y php-pear php8.3-dev git > /dev/null + + +WORKDIR /workerman +COPY --link . . + + +RUN composer require swow/swow > /dev/null +RUN ./vendor/bin/swow-builder --install > /dev/null +RUN echo extension=swow.so > /etc/php/8.3/cli/conf.d/20-swow.ini +RUN composer install --optimize-autoloader --classmap-authoritative --no-dev --quiet +COPY php-jit.ini /etc/php/8.3/cli/conf.d/10-opcache.ini + +EXPOSE 8080 + + +CMD php /workerman/server.php start diff --git a/frameworks/PHP/workerman/workerman-pgsql.dockerfile b/frameworks/PHP/workerman/workerman-pgsql.dockerfile index 9b1552d354e..fc12352dd8f 100644 --- a/frameworks/PHP/workerman/workerman-pgsql.dockerfile +++ b/frameworks/PHP/workerman/workerman-pgsql.dockerfile @@ -1,6 +1,7 @@ FROM ubuntu:24.04 ENV TEST_TYPE pgsql +ENV PROCESS_MULTIPLIER 4 ARG DEBIAN_FRONTEND=noninteractive diff --git a/frameworks/PHP/workerman/workerman.dockerfile b/frameworks/PHP/workerman/workerman.dockerfile index a4d9602019e..6cff7987f3a 100644 --- a/frameworks/PHP/workerman/workerman.dockerfile +++ b/frameworks/PHP/workerman/workerman.dockerfile @@ -1,6 +1,7 @@ FROM ubuntu:24.04 ENV TEST_TYPE default +ENV PROCESS_MULTIPLIER 1 ARG DEBIAN_FRONTEND=noninteractive From aecc2a43c4d014eda04573f265019800cfc361bc Mon Sep 17 00:00:00 2001 From: Petrik de Heus Date: Mon, 4 Nov 2024 19:39:05 +0100 Subject: [PATCH 192/204] [crystal/lucky] Fix tests and update dependencies (#9380) Reduce connection pool size to avoid connection errors like: psycopg2.OperationalError: connection to server at "10.0.0.2", port 5432 failed: FATAL: sorry, too many clients already --- frameworks/Crystal/lucky/lucky.dockerfile | 4 ++-- frameworks/Crystal/lucky/shard.lock | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/frameworks/Crystal/lucky/lucky.dockerfile b/frameworks/Crystal/lucky/lucky.dockerfile index 8309958ace4..1f352cf53bd 100644 --- a/frameworks/Crystal/lucky/lucky.dockerfile +++ b/frameworks/Crystal/lucky/lucky.dockerfile @@ -1,4 +1,4 @@ -FROM crystallang/crystal:1.12.1 +FROM crystallang/crystal:1.14.0 WORKDIR /lucky COPY shard.lock shard.lock @@ -14,7 +14,7 @@ ENV LUCKY_ENV production RUN shards build bench --release --no-debug -ENV DATABASE_URL postgres://benchmarkdbuser:benchmarkdbpass@tfb-database:5432/hello_world?initial_pool_size=56&max_idle_pool_size=56 +ENV DATABASE_URL postgres://benchmarkdbuser:benchmarkdbpass@tfb-database:5432/hello_world?initial_pool_size=10&max_idle_pool_size=10 EXPOSE 8080 diff --git a/frameworks/Crystal/lucky/shard.lock b/frameworks/Crystal/lucky/shard.lock index 86720033909..34f8bfcfea6 100644 --- a/frameworks/Crystal/lucky/shard.lock +++ b/frameworks/Crystal/lucky/shard.lock @@ -2,7 +2,7 @@ version: 2.0 shards: avram: git: https://github.com/luckyframework/avram.git - version: 1.2.0 + version: 1.3.0 backtracer: git: https://github.com/sija/backtracer.cr.git @@ -30,7 +30,7 @@ shards: habitat: git: https://github.com/luckyframework/habitat.git - version: 0.4.8 + version: 0.4.9 lucky: git: https://github.com/luckyframework/lucky.git @@ -66,7 +66,7 @@ shards: splay_tree_map: git: https://github.com/wyhaines/splay_tree_map.cr.git - version: 0.2.2 + version: 0.3.0 wordsmith: git: https://github.com/luckyframework/wordsmith.git From 992475cec3f7011d570a1131c83ad8e07e95bec9 Mon Sep 17 00:00:00 2001 From: Andrew James <59655451+andrew-james-dev@users.noreply.github.com> Date: Mon, 4 Nov 2024 18:39:33 +0000 Subject: [PATCH 193/204] Axum perf improvements (#9379) * perf: switch plaintext and json to one runtime per thread, improving performance. * perf: remove need for additional vec * perf: reduce length of query parameter * perf: increase strength of inlining hint * perf: reduce query length * perf: shorten path and use references * bug: increased length of route in line with requirements --- frameworks/Rust/axum/benchmark_config.json | 18 +++++++++--------- frameworks/Rust/axum/src/common/mod.rs | 4 ++-- frameworks/Rust/axum/src/common/utils.rs | 5 +++-- frameworks/Rust/axum/src/main.rs | 9 ++++++--- frameworks/Rust/axum/src/main_sqlx.rs | 10 ++++++---- frameworks/Rust/axum/src/pg/database.rs | 17 +++++++---------- 6 files changed, 33 insertions(+), 30 deletions(-) diff --git a/frameworks/Rust/axum/benchmark_config.json b/frameworks/Rust/axum/benchmark_config.json index ade60875389..c33a1edad78 100755 --- a/frameworks/Rust/axum/benchmark_config.json +++ b/frameworks/Rust/axum/benchmark_config.json @@ -28,7 +28,7 @@ "docker_cmd": "/app/axum-sqlx", "db_url": "/db", "fortune_url": "/fortunes", - "cached_query_url": "/cached-queries?queries=", + "cached_query_url": "/cached-queries?q=", "port": 8000, "approach": "Realistic", "classification": "Fullstack", @@ -50,8 +50,8 @@ "docker_cmd": "/app/axum-pg", "db_url": "/db", "fortune_url": "/fortunes", - "query_url": "/queries?queries=", - "update_url": "/updates?queries=", + "query_url": "/queries?q=", + "update_url": "/updates?q=", "port": 8000, "approach": "Realistic", "classification": "Fullstack", @@ -72,8 +72,8 @@ "dockerfile": "axum.dockerfile", "docker_cmd": "/app/axum-pg-pool", "db_url": "/db", - "query_url": "/queries?queries=", - "update_url": "/updates?queries=", + "query_url": "/queries?q=", + "update_url": "/updates?q=", "fortune_url": "/fortunes", "port": 8000, "approach": "Realistic", @@ -95,9 +95,9 @@ "dockerfile": "axum.dockerfile", "docker_cmd": "/app/axum-mongo", "db_url": "/db", - "query_url": "/queries?queries=", + "query_url": "/queries?q=", "fortune_url": "/fortunes", - "update_url": "/updates?queries=", + "update_url": "/updates?q=", "port": 8000, "approach": "Realistic", "classification": "Fullstack", @@ -118,8 +118,8 @@ "dockerfile": "axum.dockerfile", "docker_cmd": "/app/axum-mongo-raw", "db_url": "/db", - "query_url": "/queries?queries=", - "update_url": "/updates?queries=", + "query_url": "/queries?q=", + "update_url": "/updates?q=", "port": 8000, "approach": "Realistic", "classification": "Fullstack", diff --git a/frameworks/Rust/axum/src/common/mod.rs b/frameworks/Rust/axum/src/common/mod.rs index d55958155f1..808b2a70eeb 100644 --- a/frameworks/Rust/axum/src/common/mod.rs +++ b/frameworks/Rust/axum/src/common/mod.rs @@ -36,14 +36,14 @@ where /// Generate a single integer in the range 1 to 10,000 (inclusive) #[allow(dead_code)] -#[inline] +#[inline(always)] pub fn random_id(rng: &mut SmallRng) -> i32 { rng.gen_range(1..10_001) } /// Generate vector of integers in the range 1 to 10,000 (inclusive) #[allow(dead_code)] -#[inline] +#[inline(always)] pub fn random_ids(rng: &mut SmallRng, count: usize) -> Vec { rng.sample_iter(Uniform::new(1, 10_001)) .take(count) diff --git a/frameworks/Rust/axum/src/common/utils.rs b/frameworks/Rust/axum/src/common/utils.rs index 063411f3da7..0da86151e62 100644 --- a/frameworks/Rust/axum/src/common/utils.rs +++ b/frameworks/Rust/axum/src/common/utils.rs @@ -7,13 +7,14 @@ use serde::Deserialize; #[derive(Debug, Deserialize)] pub struct Params { - queries: Option, + q: Option, } #[allow(dead_code)] +#[inline(always)] pub fn parse_params(params: Params) -> usize { params - .queries + .q .and_then(|q| q.parse().ok()) .unwrap_or(1) .clamp(1, 500) diff --git a/frameworks/Rust/axum/src/main.rs b/frameworks/Rust/axum/src/main.rs index 70858e27ddc..0b33fb7edcb 100644 --- a/frameworks/Rust/axum/src/main.rs +++ b/frameworks/Rust/axum/src/main.rs @@ -26,13 +26,16 @@ pub async fn json() -> impl IntoResponse { (StatusCode::OK, Json(message)) } -#[tokio::main] -async fn main() { +fn main() { dotenv().ok(); + server::start_tokio(serve_app) +} + +async fn serve_app() { let app = Router::new() .route("/plaintext", get(plaintext)) .route("/json", get(json)); server::serve_hyper(app, Some(8000)).await -} +} \ No newline at end of file diff --git a/frameworks/Rust/axum/src/main_sqlx.rs b/frameworks/Rust/axum/src/main_sqlx.rs index 163372b83d8..b3a7937841b 100644 --- a/frameworks/Rust/axum/src/main_sqlx.rs +++ b/frameworks/Rust/axum/src/main_sqlx.rs @@ -1,6 +1,8 @@ mod common; mod sqlx; +use std::sync::Arc; + use ::sqlx::PgPool; use axum::{ extract::{Query, State}, @@ -56,7 +58,7 @@ async fn queries( let ids = random_ids(&mut rng, count); let mut worlds: Vec = Vec::with_capacity(count); - for id in ids { + for id in &ids { let world: World = ::sqlx::query_as(common::SELECT_WORLD_BY_ID) .bind(id) .fetch_one(&mut *db.acquire().await.unwrap()) @@ -96,7 +98,7 @@ async fn cache( ) -> impl IntoResponse { let count = parse_params(params); let mut rng = SmallRng::from_rng(&mut thread_rng()).unwrap(); - let mut worlds: Vec> = Vec::with_capacity(count); + let mut worlds: Vec>> = Vec::with_capacity(count); for id in random_ids(&mut rng, count) { worlds.push(cache.get(&id).await); @@ -113,7 +115,7 @@ async fn preload_cache(AppState { db, cache }: &AppState) { .expect("error loading worlds"); for world in worlds { - cache.insert(world.id, world).await; + cache.insert(world.id, Arc::new(world)).await; } } @@ -121,7 +123,7 @@ async fn preload_cache(AppState { db, cache }: &AppState) { #[derive(Clone)] struct AppState { db: PgPool, - cache: Cache, + cache: Cache>, } #[tokio::main] diff --git a/frameworks/Rust/axum/src/pg/database.rs b/frameworks/Rust/axum/src/pg/database.rs index bc78b2ba5c8..b9cff086c5a 100644 --- a/frameworks/Rust/axum/src/pg/database.rs +++ b/frameworks/Rust/axum/src/pg/database.rs @@ -90,21 +90,18 @@ impl PgConnection { } pub async fn update_worlds(&self, num: usize) -> Result, PgError> { - let worlds = self.fetch_random_worlds(num).await?; + let mut worlds = self.fetch_random_worlds(num).await?; // Update the worlds with new random numbers let mut rng = SmallRng::from_rng(&mut thread_rng()).unwrap(); let mut ids = Vec::with_capacity(num); let mut nids = Vec::with_capacity(num); - let worlds: Vec = worlds - .into_iter() - .map(|mut w| { - w.randomnumber = random_id(&mut rng); - ids.push(w.id); - nids.push(w.randomnumber); - w - }) - .collect(); + + for w in &mut worlds { + w.randomnumber = random_id(&mut rng); + ids.push(w.id); + nids.push(w.randomnumber); + } // Update the random worlds in the database. self.client From edeb2d8794e4aa14ed55975709ebf37e31ae95ff Mon Sep 17 00:00:00 2001 From: Santiago Pericas-Geertsen Date: Mon, 4 Nov 2024 13:40:05 -0500 Subject: [PATCH 194/204] Some improvements to Db tests (#9378) * New updates logic. Signed-off-by: Santiago Pericas-Geertsen * Set pipelining. Signed-off-by: Santiago Pericas-Geertsen --------- Signed-off-by: Santiago Pericas-Geertsen --- .../benchmark/nima/models/DbRepository.java | 8 -- .../nima/models/HikariJdbcRepository.java | 9 -- .../nima/models/PgClientRepository.java | 124 ++++++------------ .../helidon/benchmark/nima/models/World.java | 14 -- .../nima/src/main/resources/application.yaml | 4 - 5 files changed, 43 insertions(+), 116 deletions(-) diff --git a/frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/models/DbRepository.java b/frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/models/DbRepository.java index d1f75b558c3..41af9c03b8e 100644 --- a/frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/models/DbRepository.java +++ b/frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/models/DbRepository.java @@ -1,23 +1,15 @@ package io.helidon.benchmark.nima.models; -import java.util.Collections; import java.util.List; import java.util.concurrent.ThreadLocalRandom; -import jakarta.json.Json; -import jakarta.json.JsonBuilderFactory; - public interface DbRepository { - JsonBuilderFactory JSON = Json.createBuilderFactory(Collections.emptyMap()); - World getWorld(int id); List getWorlds(int count); - World updateWorld(World world); - List updateWorlds(int count); List getFortunes(); diff --git a/frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/models/HikariJdbcRepository.java b/frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/models/HikariJdbcRepository.java index fd9760939df..7bf7e8c72b8 100644 --- a/frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/models/HikariJdbcRepository.java +++ b/frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/models/HikariJdbcRepository.java @@ -80,15 +80,6 @@ public List getWorlds(int count) { } } - @Override - public World updateWorld(World world) { - try (Connection c = getConnection()) { - return updateWorld(world, c); - } catch (Exception e) { - throw new RuntimeException(e); - } - } - @Override public List updateWorlds(int count) { try (Connection c = getConnection()) { diff --git a/frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/models/PgClientRepository.java b/frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/models/PgClientRepository.java index e5166b10fbc..291131eca17 100644 --- a/frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/models/PgClientRepository.java +++ b/frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/models/PgClientRepository.java @@ -2,17 +2,13 @@ import java.util.ArrayList; import java.util.List; -import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; import java.util.logging.Logger; import io.helidon.config.Config; - +import io.vertx.core.Future; import io.vertx.core.Vertx; import io.vertx.core.VertxOptions; -import io.vertx.core.Future; import io.vertx.pgclient.PgConnectOptions; import io.vertx.pgclient.PgPool; import io.vertx.sqlclient.PoolOptions; @@ -26,45 +22,40 @@ public class PgClientRepository implements DbRepository { private static final Logger LOGGER = Logger.getLogger(PgClientRepository.class.getName()); + private static final int UPDATE_QUERIES = 500; - private final SqlClient queryPool; private final SqlClient updatePool; - private final int batchSize; - private final long updateTimeout; - private final int maxRetries; - private final PreparedQuery> getFortuneQuery; private final PreparedQuery> getWorldQuery; - private final PreparedQuery> updateWorldQuery; + private final PreparedQuery>[] updateWorldSingleQuery; + @SuppressWarnings("unchecked") public PgClientRepository(Config config) { - Vertx vertx = Vertx.vertx(new VertxOptions() - .setPreferNativeTransport(true)); + Vertx vertx = Vertx.vertx(new VertxOptions().setPreferNativeTransport(true)); PgConnectOptions connectOptions = new PgConnectOptions() .setPort(config.get("port").asInt().orElse(5432)) .setCachePreparedStatements(config.get("cache-prepared-statements").asBoolean().orElse(true)) .setHost(config.get("host").asString().orElse("tfb-database")) .setDatabase(config.get("db").asString().orElse("hello_world")) .setUser(config.get("username").asString().orElse("benchmarkdbuser")) - .setPassword(config.get("password").asString().orElse("benchmarkdbpass")); + .setPassword(config.get("password").asString().orElse("benchmarkdbpass")) + .setPipeliningLimit(100000); int sqlPoolSize = config.get("sql-pool-size").asInt().orElse(64); PoolOptions clientOptions = new PoolOptions().setMaxSize(sqlPoolSize); LOGGER.info("sql-pool-size is " + sqlPoolSize); - batchSize = config.get("update-batch-size").asInt().orElse(20); - LOGGER.info("update-batch-size is " + batchSize); - updateTimeout = config.get("update-timeout-millis").asInt().orElse(5000); - LOGGER.info("update-timeout-millis is " + updateTimeout); - maxRetries = config.get("update-max-retries").asInt().orElse(3); - LOGGER.info("update-max-retries is " + maxRetries); - - queryPool = PgPool.client(vertx, connectOptions, clientOptions); + + SqlClient queryPool = PgPool.client(vertx, connectOptions, clientOptions); updatePool = PgPool.client(vertx, connectOptions, clientOptions); getWorldQuery = queryPool.preparedQuery("SELECT id, randomnumber FROM world WHERE id = $1"); - updateWorldQuery = queryPool.preparedQuery("UPDATE world SET randomnumber = $1 WHERE id = $2"); getFortuneQuery = queryPool.preparedQuery("SELECT id, message FROM fortune"); + + updateWorldSingleQuery = new PreparedQuery[UPDATE_QUERIES]; + for (int i = 0; i < UPDATE_QUERIES; i++) { + updateWorldSingleQuery[i] = queryPool.preparedQuery(singleUpdate(i + 1)); + } } @Override @@ -97,60 +88,11 @@ public List getWorlds(int count) { } } - @Override - public World updateWorld(World world) { - try { - return updateWorldQuery.execute(Tuple.of(world.id, world.id)) - .toCompletionStage() - .thenApply(rows -> world) - .toCompletableFuture().get(); - } catch (Exception e) { - throw new RuntimeException(e); - } - } - @Override public List updateWorlds(int count) { List worlds = getWorlds(count); - if (batchSize > 1) { // batching updates - for (World w : worlds) { - w.randomNumber = randomWorldNumber(); - } - if (count <= batchSize) { - LOGGER.finest(() -> "Updating single batch of size " + count); - updateWorldsRetry(worlds, 0, 0); - } else { - int batches = count / batchSize + (count % batchSize == 0 ? 0 : 1); - for (int i = 0; i < batches; i++) { - final int from = i * batchSize; - LOGGER.finest(() -> "Updating batch from " + from + " to " + (from + batchSize)); - updateWorldsRetry(worlds, from, 0); - } - } - } else { // no batching for size 1 - for (World w : worlds) { - w.randomNumber = randomWorldNumber(); - updateWorld(w); - } - } - return worlds; - } - - private List updateWorldsRetry(List worlds, int from, int retries) { - if (retries > maxRetries) { - throw new RuntimeException("Too many transaction retries"); - } - CompletableFuture> cf = null; try { - cf = updateWorlds(worlds, from, updatePool); - cf.get(updateTimeout, TimeUnit.MILLISECONDS); - return worlds; - } catch (ExecutionException | TimeoutException e) { - cf.cancel(true); - retries++; - final int finalRetries = retries; - LOGGER.fine(() -> "Retrying batch update after cancellation (retries=" + finalRetries + ")"); - return updateWorldsRetry(worlds, from, retries); // retry + return updateWorlds(worlds, count, updatePool); } catch (Exception e) { throw new RuntimeException(e); } @@ -172,16 +114,36 @@ public List getFortunes() { } } - private CompletableFuture> updateWorlds(List worlds, int from, SqlClient pool) { - List tuples = new ArrayList<>(); - int to = Math.min(from + batchSize, worlds.size()); - for (int i = from; i < to; i++) { - World w = worlds.get(i); - tuples.add(Tuple.of(w.randomNumber, w.id)); + private List updateWorlds(List worlds, int count, SqlClient pool) + throws ExecutionException, InterruptedException { + int size = worlds.size(); + List updateParams = new ArrayList<>(size * 2); + for (World world : worlds) { + updateParams.add(world.id); + world.randomNumber = randomWorldNumber(); + updateParams.add(world.randomNumber); } - return updateWorldQuery.executeBatch(tuples) + return updateWorldSingleQuery[count - 1].execute(Tuple.wrap(updateParams)) .toCompletionStage() .thenApply(rows -> worlds) - .toCompletableFuture(); + .toCompletableFuture() + .get(); + } + + private static String singleUpdate(int count) { + StringBuilder sql = new StringBuilder(); + sql.append("UPDATE WORLD SET RANDOMNUMBER = CASE ID"); + for (int i = 0; i < count; i++) { + int k = i * 2 + 1; + sql.append(" WHEN $").append(k).append(" THEN $").append(k + 1); + } + sql.append(" ELSE RANDOMNUMBER"); + sql.append(" END WHERE ID IN ($1"); + for (int i = 1; i < count; i++) { + int k = i * 2 + 1; + sql.append(",$").append(k); + } + sql.append(")"); + return sql.toString(); } } \ No newline at end of file diff --git a/frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/models/World.java b/frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/models/World.java index 39deafea11b..dbcba61a8ca 100644 --- a/frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/models/World.java +++ b/frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/models/World.java @@ -1,18 +1,8 @@ package io.helidon.benchmark.nima.models; -import java.util.Collections; - -import jakarta.json.Json; -import jakarta.json.JsonBuilderFactory; -import jakarta.json.JsonObject; - public final class World { - static final String ID_KEY = "id"; - static final String ID_RANDOM_NUMBER = "randomNumber"; - static final JsonBuilderFactory JSON = Json.createBuilderFactory(Collections.emptyMap()); - public int id; public int randomNumber; @@ -20,8 +10,4 @@ public World(int id, int randomNumber) { this.id = id; this.randomNumber = randomNumber; } - - public JsonObject toJson() { - return JSON.createObjectBuilder().add(ID_KEY, id).add(ID_RANDOM_NUMBER, randomNumber).build(); - } } diff --git a/frameworks/Java/helidon/nima/src/main/resources/application.yaml b/frameworks/Java/helidon/nima/src/main/resources/application.yaml index 41f4d64ec12..d2d8e8943b4 100644 --- a/frameworks/Java/helidon/nima/src/main/resources/application.yaml +++ b/frameworks/Java/helidon/nima/src/main/resources/application.yaml @@ -39,7 +39,3 @@ password: benchmarkdbpass sql-pool-size: 300 db-repository: "pgclient" # "pgclient" (default) or "hikari" -# The following for pgclient only -update-batch-size: 4 -update-timeout-millis: 10000 -update-max-retries: 3 From d91f0176a733252c75e054ec24eda2c183d5db86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Ros?= Date: Mon, 4 Nov 2024 10:40:34 -0800 Subject: [PATCH 195/204] Update dotnet version (#9376) --- .../CSharp/aspnetcore/appsettings.postgresql.json | 2 +- .../CSharp/aspnetcore/aspnetcore-aot.dockerfile | 6 +++--- .../aspnetcore/aspnetcore-minimal.dockerfile | 7 +++++-- .../CSharp/aspnetcore/aspnetcore-mvc.dockerfile | 7 +++++-- .../CSharp/aspnetcore/aspnetcore-mysql.dockerfile | 7 +++++-- frameworks/CSharp/aspnetcore/aspnetcore.dockerfile | 9 ++++++--- .../CSharp/aspnetcore/src/Minimal/Minimal.csproj | 8 ++++---- .../CSharp/aspnetcore/src/Minimal/Program.cs | 14 ++++++-------- .../Minimal/{Templates => Slices}/Fortunes.cshtml | 0 .../{Templates => Slices}/_ViewImports.cshtml | 0 frameworks/CSharp/aspnetcore/src/Mvc/Mvc.csproj | 6 +++--- .../CSharp/aspnetcore/src/Platform/Platform.csproj | 8 ++++---- .../CSharp/aspnetcore/src/Platform/Program.cs | 1 - 13 files changed, 42 insertions(+), 33 deletions(-) rename frameworks/CSharp/aspnetcore/src/Minimal/{Templates => Slices}/Fortunes.cshtml (100%) rename frameworks/CSharp/aspnetcore/src/Minimal/{Templates => Slices}/_ViewImports.cshtml (100%) diff --git a/frameworks/CSharp/aspnetcore/appsettings.postgresql.json b/frameworks/CSharp/aspnetcore/appsettings.postgresql.json index abc42e6ce8a..423af4d19b0 100644 --- a/frameworks/CSharp/aspnetcore/appsettings.postgresql.json +++ b/frameworks/CSharp/aspnetcore/appsettings.postgresql.json @@ -1,4 +1,4 @@ { - "ConnectionString": "Server=tfb-database;Database=hello_world;User Id=benchmarkdbuser;Password=benchmarkdbpass;SSL Mode=Disable;Maximum Pool Size=18;NoResetOnClose=true;Enlist=false;Max Auto Prepare=4;Multiplexing=true;Write Coalescing Buffer Threshold Bytes=1000", + "ConnectionString": "Server=tfb-database;Database=hello_world;User Id=benchmarkdbuser;Password=benchmarkdbpass;SSL Mode=Disable;Maximum Pool Size=512;NoResetOnClose=true;Enlist=false;Max Auto Prepare=4", "Database": "postgresql" } diff --git a/frameworks/CSharp/aspnetcore/aspnetcore-aot.dockerfile b/frameworks/CSharp/aspnetcore/aspnetcore-aot.dockerfile index a114ee58727..a7396e3b919 100644 --- a/frameworks/CSharp/aspnetcore/aspnetcore-aot.dockerfile +++ b/frameworks/CSharp/aspnetcore/aspnetcore-aot.dockerfile @@ -1,12 +1,12 @@ -FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build +FROM mcr.microsoft.com/dotnet/sdk:9.0 AS build RUN apt-get update RUN apt-get -yqq install clang zlib1g-dev WORKDIR /app COPY src/Platform . RUN dotnet publish -c Release -o out /p:DatabaseProvider=Npgsql /p:PublishAot=true /p:OptimizationPreference=Speed /p:GarbageCollectionAdaptationMode=0 -FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS runtime -ENV URLS http://+:8080 +FROM mcr.microsoft.com/dotnet/aspnet:9.0 AS runtime +ENV URLS=http://+:8080 WORKDIR /app COPY --from=build /app/out ./ diff --git a/frameworks/CSharp/aspnetcore/aspnetcore-minimal.dockerfile b/frameworks/CSharp/aspnetcore/aspnetcore-minimal.dockerfile index 5ab25aa2bb9..24893c9717a 100644 --- a/frameworks/CSharp/aspnetcore/aspnetcore-minimal.dockerfile +++ b/frameworks/CSharp/aspnetcore/aspnetcore-minimal.dockerfile @@ -1,10 +1,13 @@ -FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build +FROM mcr.microsoft.com/dotnet/sdk:9.0 AS build WORKDIR /app COPY src/Minimal . RUN dotnet publish -c Release -o out -FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS runtime +FROM mcr.microsoft.com/dotnet/aspnet:9.0 AS runtime ENV URLS http://+:8080 +ENV DOTNET_GCDynamicAdaptationMode=0 +ENV DOTNET_ReadyToRun=0 +ENV DOTNET_HillClimbing_Disable=1 WORKDIR /app COPY --from=build /app/out ./ diff --git a/frameworks/CSharp/aspnetcore/aspnetcore-mvc.dockerfile b/frameworks/CSharp/aspnetcore/aspnetcore-mvc.dockerfile index b0d126973cb..6922a53bf2a 100644 --- a/frameworks/CSharp/aspnetcore/aspnetcore-mvc.dockerfile +++ b/frameworks/CSharp/aspnetcore/aspnetcore-mvc.dockerfile @@ -1,10 +1,13 @@ -FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build +FROM mcr.microsoft.com/dotnet/sdk:9.0 AS build WORKDIR /app COPY src/Mvc . RUN dotnet publish -c Release -o out -FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS runtime +FROM mcr.microsoft.com/dotnet/aspnet:9.0 AS runtime ENV URLS http://+:8080 +ENV DOTNET_GCDynamicAdaptationMode=0 +ENV DOTNET_ReadyToRun=0 +ENV DOTNET_HillClimbing_Disable=1 WORKDIR /app COPY --from=build /app/out ./ diff --git a/frameworks/CSharp/aspnetcore/aspnetcore-mysql.dockerfile b/frameworks/CSharp/aspnetcore/aspnetcore-mysql.dockerfile index 505414aa173..ecc0a8331c3 100644 --- a/frameworks/CSharp/aspnetcore/aspnetcore-mysql.dockerfile +++ b/frameworks/CSharp/aspnetcore/aspnetcore-mysql.dockerfile @@ -1,10 +1,13 @@ -FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build +FROM mcr.microsoft.com/dotnet/sdk:9.0 AS build WORKDIR /app COPY src/Platform . RUN dotnet publish -c Release -o out /p:DatabaseProvider=MySqlConnector -FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS runtime +FROM mcr.microsoft.com/dotnet/aspnet:9.0 AS runtime ENV URLS http://+:8080 +ENV DOTNET_GCDynamicAdaptationMode=0 +ENV DOTNET_ReadyToRun=0 +ENV DOTNET_HillClimbing_Disable=1 WORKDIR /app COPY --from=build /app/out ./ diff --git a/frameworks/CSharp/aspnetcore/aspnetcore.dockerfile b/frameworks/CSharp/aspnetcore/aspnetcore.dockerfile index 5a846103428..64510ffe786 100644 --- a/frameworks/CSharp/aspnetcore/aspnetcore.dockerfile +++ b/frameworks/CSharp/aspnetcore/aspnetcore.dockerfile @@ -1,10 +1,13 @@ -FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build +FROM mcr.microsoft.com/dotnet/sdk:9.0 AS build WORKDIR /app COPY src/Platform . RUN dotnet publish -c Release -o out /p:DatabaseProvider=Npgsql -FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS runtime -ENV URLS http://+:8080 +FROM mcr.microsoft.com/dotnet/aspnet:9.0 AS runtime +ENV URLS=http://+:8080 +ENV DOTNET_GCDynamicAdaptationMode=0 +ENV DOTNET_ReadyToRun=0 +ENV DOTNET_HillClimbing_Disable=1 WORKDIR /app COPY --from=build /app/out ./ diff --git a/frameworks/CSharp/aspnetcore/src/Minimal/Minimal.csproj b/frameworks/CSharp/aspnetcore/src/Minimal/Minimal.csproj index 783ec88ff32..01ed70de876 100644 --- a/frameworks/CSharp/aspnetcore/src/Minimal/Minimal.csproj +++ b/frameworks/CSharp/aspnetcore/src/Minimal/Minimal.csproj @@ -1,7 +1,7 @@  - net8.0 + net9.0 enable enable latest @@ -9,9 +9,9 @@ - - - + + + diff --git a/frameworks/CSharp/aspnetcore/src/Minimal/Program.cs b/frameworks/CSharp/aspnetcore/src/Minimal/Program.cs index 9ac63edcca2..7aaac6db1ac 100644 --- a/frameworks/CSharp/aspnetcore/src/Minimal/Program.cs +++ b/frameworks/CSharp/aspnetcore/src/Minimal/Program.cs @@ -1,13 +1,11 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. -using System.Text.Encodings.Web; -using System.Text.Unicode; -using Microsoft.AspNetCore.Http.HttpResults; -using RazorSlices; using Minimal; using Minimal.Database; using Minimal.Models; +using System.Text.Encodings.Web; +using System.Text.Unicode; var builder = WebApplication.CreateBuilder(args); @@ -36,14 +34,14 @@ app.MapGet("/db", async (Db db) => await db.LoadSingleQueryRow()); -var createFortunesTemplate = RazorSlice.ResolveSliceFactory>("/Templates/Fortunes.cshtml"); var htmlEncoder = CreateHtmlEncoder(); app.MapGet("/fortunes", async (HttpContext context, Db db) => { var fortunes = await db.LoadFortunesRows(); - var template = (RazorSliceHttpResult>)createFortunesTemplate(fortunes); - template.HtmlEncoder = htmlEncoder; - return template; + var result = Results.Extensions.RazorSlice>(fortunes); + result.HtmlEncoder = htmlEncoder; + + return result; }); app.MapGet("/queries/{count?}", async (Db db, string? count) => await db.LoadMultipleQueriesRows(count)); diff --git a/frameworks/CSharp/aspnetcore/src/Minimal/Templates/Fortunes.cshtml b/frameworks/CSharp/aspnetcore/src/Minimal/Slices/Fortunes.cshtml similarity index 100% rename from frameworks/CSharp/aspnetcore/src/Minimal/Templates/Fortunes.cshtml rename to frameworks/CSharp/aspnetcore/src/Minimal/Slices/Fortunes.cshtml diff --git a/frameworks/CSharp/aspnetcore/src/Minimal/Templates/_ViewImports.cshtml b/frameworks/CSharp/aspnetcore/src/Minimal/Slices/_ViewImports.cshtml similarity index 100% rename from frameworks/CSharp/aspnetcore/src/Minimal/Templates/_ViewImports.cshtml rename to frameworks/CSharp/aspnetcore/src/Minimal/Slices/_ViewImports.cshtml diff --git a/frameworks/CSharp/aspnetcore/src/Mvc/Mvc.csproj b/frameworks/CSharp/aspnetcore/src/Mvc/Mvc.csproj index 5bffd479c0f..83105ed34be 100644 --- a/frameworks/CSharp/aspnetcore/src/Mvc/Mvc.csproj +++ b/frameworks/CSharp/aspnetcore/src/Mvc/Mvc.csproj @@ -1,7 +1,7 @@  - net8.0 + net9.0 enable enable latest @@ -9,8 +9,8 @@ - - + + diff --git a/frameworks/CSharp/aspnetcore/src/Platform/Platform.csproj b/frameworks/CSharp/aspnetcore/src/Platform/Platform.csproj index 548e446ee0a..ef14e44b865 100644 --- a/frameworks/CSharp/aspnetcore/src/Platform/Platform.csproj +++ b/frameworks/CSharp/aspnetcore/src/Platform/Platform.csproj @@ -1,7 +1,7 @@  - net8.0 + net9.0 true true preview @@ -19,9 +19,9 @@
    - - - + + + diff --git a/frameworks/CSharp/aspnetcore/src/Platform/Program.cs b/frameworks/CSharp/aspnetcore/src/Platform/Program.cs index 9b22d3f5b40..28fc5d757dd 100644 --- a/frameworks/CSharp/aspnetcore/src/Platform/Program.cs +++ b/frameworks/CSharp/aspnetcore/src/Platform/Program.cs @@ -52,7 +52,6 @@ public static IWebHost BuildWebHost(string[] args) #if DEBUG .AddUserSecrets() #endif - .AddEnvironmentVariables() .AddEnvironmentVariables() .AddCommandLine(args) .Build(); From de4bda3ab71cd1fb44a1362cb0df1976873ea27c Mon Sep 17 00:00:00 2001 From: Shreck Ye Date: Tue, 5 Nov 2024 02:42:01 +0800 Subject: [PATCH 196/204] Use the new Exposed SELECT DSL in the "ktor-exposed" benchmarks, and bump the Exposed version to the latest (#9375) Add `--no-daemon` to the Dockerfile Gradle commands BTW. --- frameworks/Kotlin/ktor/ktor-exposed-dao.dockerfile | 2 +- frameworks/Kotlin/ktor/ktor-exposed-dsl.dockerfile | 2 +- frameworks/Kotlin/ktor/ktor-exposed/app/build.gradle.kts | 2 +- .../Kotlin/ktor/ktor-exposed/app/src/main/kotlin/App.kt | 9 ++++++--- 4 files changed, 9 insertions(+), 6 deletions(-) diff --git a/frameworks/Kotlin/ktor/ktor-exposed-dao.dockerfile b/frameworks/Kotlin/ktor/ktor-exposed-dao.dockerfile index e12a664f8dc..10f2ed2180d 100644 --- a/frameworks/Kotlin/ktor/ktor-exposed-dao.dockerfile +++ b/frameworks/Kotlin/ktor/ktor-exposed-dao.dockerfile @@ -3,7 +3,7 @@ FROM gradle:jdk17 WORKDIR /ktor-exposed COPY ktor-exposed/settings.gradle.kts settings.gradle.kts COPY ktor-exposed/app app -RUN gradle shadowJar +RUN gradle --no-daemon shadowJar EXPOSE 8080 diff --git a/frameworks/Kotlin/ktor/ktor-exposed-dsl.dockerfile b/frameworks/Kotlin/ktor/ktor-exposed-dsl.dockerfile index f65069e6b78..5d05b4494ce 100644 --- a/frameworks/Kotlin/ktor/ktor-exposed-dsl.dockerfile +++ b/frameworks/Kotlin/ktor/ktor-exposed-dsl.dockerfile @@ -3,7 +3,7 @@ FROM gradle:jdk17 WORKDIR /ktor-exposed COPY ktor-exposed/settings.gradle.kts settings.gradle.kts COPY ktor-exposed/app app -RUN gradle shadowJar +RUN gradle --no-daemon shadowJar EXPOSE 8080 diff --git a/frameworks/Kotlin/ktor/ktor-exposed/app/build.gradle.kts b/frameworks/Kotlin/ktor/ktor-exposed/app/build.gradle.kts index 60f4dab3b17..f57ded6c314 100644 --- a/frameworks/Kotlin/ktor/ktor-exposed/app/build.gradle.kts +++ b/frameworks/Kotlin/ktor/ktor-exposed/app/build.gradle.kts @@ -11,7 +11,7 @@ repositories { val ktorVersion = "2.3.12" val kotlinxSerializationVersion = "1.6.3" -val exposedVersion = "0.52.0" +val exposedVersion = "0.56.0" dependencies { implementation("io.ktor:ktor-server-core:$ktorVersion") diff --git a/frameworks/Kotlin/ktor/ktor-exposed/app/src/main/kotlin/App.kt b/frameworks/Kotlin/ktor/ktor-exposed/app/src/main/kotlin/App.kt index c284ecd7b17..513a20b7ab7 100644 --- a/frameworks/Kotlin/ktor/ktor-exposed/app/src/main/kotlin/App.kt +++ b/frameworks/Kotlin/ktor/ktor-exposed/app/src/main/kotlin/App.kt @@ -19,9 +19,12 @@ import org.jetbrains.exposed.dao.IntEntity import org.jetbrains.exposed.dao.IntEntityClass import org.jetbrains.exposed.dao.id.EntityID import org.jetbrains.exposed.dao.id.IdTable -import org.jetbrains.exposed.sql.* +import org.jetbrains.exposed.sql.Database +import org.jetbrains.exposed.sql.ResultRow import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq +import org.jetbrains.exposed.sql.Transaction import org.jetbrains.exposed.sql.transactions.transaction +import org.jetbrains.exposed.sql.update import java.util.concurrent.ThreadLocalRandom @Serializable @@ -82,7 +85,7 @@ fun Application.module(exposedMode: ExposedMode) { routing { fun selectWorldsWithIdQuery(id: Int) = - WorldTable.slice(WorldTable.id, WorldTable.randomNumber).select(WorldTable.id eq id) + WorldTable.select(WorldTable.id, WorldTable.randomNumber).where(WorldTable.id eq id) fun ResultRow.toWorld() = World(this[WorldTable.id].value, this[WorldTable.randomNumber]) @@ -129,7 +132,7 @@ fun Application.module(exposedMode: ExposedMode) { get("/fortunes") { val result = withDatabaseContextAndTransaction { when (exposedMode) { - Dsl -> FortuneTable.slice(FortuneTable.id, FortuneTable.message).selectAll() + Dsl -> FortuneTable.select(FortuneTable.id, FortuneTable.message) .asSequence().map { it.toFortune() } Dao -> FortuneDao.all().asSequence().map { it.toFortune() } From fed744bee12c697ece997c5dba71fa9b036291ee Mon Sep 17 00:00:00 2001 From: Shreck Ye Date: Tue, 5 Nov 2024 02:42:14 +0800 Subject: [PATCH 197/204] Revamp the Kotlin Vert.x portions "vertx-web-kotlinx" and "vertx-web-kotlin-coroutines" (#9374) * Revamp the "vertx-web-kotlinx" portion project Changes: 1. bump the Gradle versions and the dependency versions to the latest 1. bump the JVM version to 21 with the new `jvmToolchain` DSL 1. resolve deprecations 1. update the dockerfile to use the `installDist` Gradle task so the time for archiving and unarchiving is saved * Run the revamped benchmark There are no build or runtime errors. Single query performance seems to have been improved by 2% with the bumped versions (I think most likely due to Java 21). Vagrant reduces performance by about 20% compared to running directly with Docker. * Enable io_uring and run the benchmark The single query performance is improved by 5% - 10%. * Try fixing the performance issues of the "vertx-web-kotlinx" portion in the "single query" and "JSON serialization" tests in the [Continuous Benchmarking results](https://tfb-status.techempower.com/) by using static kotlinx.serialization serializers The "vertx-web-kotlinx" results in the Continuous Benchmarking results are much lower than those of the "vertx-web-kotlin-coroutines" portion. See [the latest results](https://www.techempower.com/benchmarks/#section=test&runid=592cab59-a9db-463b-a9c9-33d2f9484e92&hw=ph&test=db) for example. Looking at the "single query" results, I first suspected that it was caused by there being not enough memory for the JVM runtime, so I added some logging code that prints the memory usage using `Runtime.totalMemory` and `Runtime.maxMemory`. It showed that there was about 7 GB max memory available during the benchmark runs, and the program only used 400 MB to 1 GB. I then tried allocating a 4 GB array during the run to ensure that the memory was usable and it worked with no problem. Then looking at the "JSON serialization" results again, I saw that "vertx-web-kotlinx" performs a lot worse in this test too, and decided that this is more likely to be the bottleneck. Therefore, the static serializers are provided explicitly and the performance is improved slightly as tested on my machine. (Also, see commit 315b4e359cde7909810a6a842ae3c7d49233291f for an attempt before.) I then copied the "JSON serialization" test code from "vertx-web-kotlin-coroutines" and ran the benchmark to see if there were other factors, such as project configuration differences, affecting the performance, and the answer was no. On my machine, the "JSON serialization" performance of "vertx-web-kotlinx" is about 80% - 85% of that of "vertx-web-kotlin-coroutines". And I think the bottleneck possibly lies in kotlinx.serialization serializing an object to a byte array first and then copying it to a Vert.x buffer. Remove the broken tag in "vertx-web-kotlin-coroutines" BTW, which was added in commit e53e0260e522106b316d8fce2e378a056d866356, for the benchmark runs without problems now as I tested. * Update README.md correspondingly * Add `--no-daemon` to the Gradle command in the Dockerfiles * Update the "Connection reset" exception to the io_uring one that's ignored in logging * Use `encodeToBufferedSink` in "kotlinx-serialization-json-okio" with a custom-implemented `VertxBufferSink` in JSON serialization The "JSON serialization" performance is on par with using `io.vertx.core.json.Json.encodeToBuffer` as tested on my machine after this change. * Replace Okio with kotlinx-io and remove unneeded code The "JSON serialization" performance seems to be slightly less. * Rename 2 classes to clarify * Use to the new Vert.x coroutine APIs introduced in https://github.com/vert-x3/vertx-lang-kotlin/pull/253 / https://github.com/vert-x3/vertx-lang-kotlin/commit/e841975ef50b6be9b516d27498821096a3ad462e There is no noticeable performance degradation in the "plaintext" and "JSON serialization" tests. * Simply the code introduced in the previous commit by making `MainVerticle` implement `CoroutineRouterSupport` I didn't go through [the docs](https://vertx.io/docs/vertx-lang-kotlin-coroutines/kotlin/#_vert_x_web) thoroughly before implementing this. * Revamp the "vertx-web-kotlin-coroutines" portion project too following the changes made to the "vertx-web-kotlinx" portion The "gradlew" script somehow had incorrect access permissions and is fixed by bumping the Gradle wrapper. To keep the dependencies consistent with the "vert-web" portion, some dependencies are not updated to the latest versions. Remove 2 useless `COPY`s in "vertx-web-kotlin-coroutines-postgres.dockerfile" BTW. * Remove unneeded and incorrect comments Wrapping something as a Vert.x `Buffer` by implementing the `Buffer` interface is not viable because `BufferImpl` contains casts from a `Buffer` to a `BufferImpl`. --- .../benchmark_config.json | 3 +- .../build.gradle.kts | 25 ++--- .../gradle/wrapper/gradle-wrapper.jar | Bin 61574 -> 43583 bytes .../gradle/wrapper/gradle-wrapper.properties | 3 +- .../vertx-web-kotlin-coroutines/gradlew | 34 +++--- .../vertx-web-kotlin-coroutines/gradlew.bat | 22 ++-- ...-web-kotlin-coroutines-postgres.dockerfile | 4 +- .../vertx-web-kotlin-coroutines.dockerfile | 2 +- frameworks/Kotlin/vertx-web-kotlinx/README.md | 3 +- .../Kotlin/vertx-web-kotlinx/build.gradle.kts | 27 ++--- .../gradle/wrapper/gradle-wrapper.jar | Bin 61608 -> 43583 bytes .../gradle/wrapper/gradle-wrapper.properties | 3 +- frameworks/Kotlin/vertx-web-kotlinx/gradlew | 34 +++--- .../Kotlin/vertx-web-kotlinx/gradlew.bat | 22 ++-- .../src/main/kotlin/KotlinxIo.kt | 47 ++++++++ .../vertx-web-kotlinx/src/main/kotlin/Main.kt | 6 +- .../src/main/kotlin/MainVerticle.kt | 100 +++++++++++------- .../src/main/kotlin/Serializers.kt | 7 ++ .../src/main/kotlin/VertxCoroutine.kt | 5 +- .../vertx-web-kotlinx-postgresql.dockerfile | 7 +- .../vertx-web-kotlinx.dockerfile | 7 +- 21 files changed, 231 insertions(+), 130 deletions(-) mode change 100644 => 100755 frameworks/Kotlin/vertx-web-kotlin-coroutines/gradlew create mode 100644 frameworks/Kotlin/vertx-web-kotlinx/src/main/kotlin/KotlinxIo.kt create mode 100644 frameworks/Kotlin/vertx-web-kotlinx/src/main/kotlin/Serializers.kt diff --git a/frameworks/Kotlin/vertx-web-kotlin-coroutines/benchmark_config.json b/frameworks/Kotlin/vertx-web-kotlin-coroutines/benchmark_config.json index d2bab14abb7..2b8ebd26c83 100644 --- a/frameworks/Kotlin/vertx-web-kotlin-coroutines/benchmark_config.json +++ b/frameworks/Kotlin/vertx-web-kotlin-coroutines/benchmark_config.json @@ -18,8 +18,7 @@ "database_os": "Linux", "display_name": "vertx-web-kotlin-coroutines", "notes": "", - "versus": "vertx-web", - "tags": ["broken"] + "versus": "vertx-web" }, "postgres": { "db_url": "/db", diff --git a/frameworks/Kotlin/vertx-web-kotlin-coroutines/build.gradle.kts b/frameworks/Kotlin/vertx-web-kotlin-coroutines/build.gradle.kts index 584f6102956..973bf6d8116 100644 --- a/frameworks/Kotlin/vertx-web-kotlin-coroutines/build.gradle.kts +++ b/frameworks/Kotlin/vertx-web-kotlin-coroutines/build.gradle.kts @@ -1,34 +1,37 @@ import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar -import org.jetbrains.kotlin.gradle.dsl.JvmTarget -import org.jetbrains.kotlin.gradle.tasks.KotlinCompile tasks.wrapper { distributionType = Wrapper.DistributionType.ALL } plugins { - kotlin("jvm") version "1.8.10" + kotlin("jvm") version "2.0.21" application id("nu.studer.rocker") version "3.0.4" - id("com.github.johnrengelman.shadow") version "7.1.2" + id("com.gradleup.shadow") version "8.3.4" } group = "io.vertx" -version = "4.3.8" +version = "4.3.8" // 4.5.10 is available, but this is not updated to be kept consistent with the "vert-web" portion repositories { mavenCentral() } dependencies { - implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.4") + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.9.0") implementation(platform("io.vertx:vertx-stack-depchain:$version")) implementation("io.vertx:vertx-core") - implementation("com.fasterxml.jackson.module:jackson-module-blackbird:2.14.2") + implementation("com.fasterxml.jackson.module:jackson-module-blackbird:2.14.2") // 2.18.1 is available, but this is not updated to be kept consistent with the "vert-web" portion implementation("io.vertx:vertx-web") implementation("io.vertx:vertx-pg-client") implementation("io.vertx:vertx-web-templ-rocker") - implementation("io.netty", "netty-transport-native-epoll", classifier = "linux-x86_64") + runtimeOnly("io.netty", "netty-transport-native-epoll", classifier = "linux-x86_64") + // not used to make the project consistent with the "vert-web" portion + /* + runtimeOnly("io.vertx:vertx-io_uring-incubator") + runtimeOnly("io.netty.incubator:netty-incubator-transport-native-io_uring:0.0.25.Final:linux-x86_64") + */ implementation("io.vertx:vertx-lang-kotlin") implementation("io.vertx:vertx-lang-kotlin-coroutines") } @@ -38,14 +41,12 @@ rocker { create("main") { templateDir.set(file("src/main/resources")) optimize.set(true) - javaVersion.set("17") + javaVersion.set("17") // kept consistent with the "vert-web" portion } } } -tasks.withType { - compilerOptions.jvmTarget.set(JvmTarget.JVM_17) -} +kotlin.jvmToolchain(17) // kept consistent with the "vert-web" portion // content below copied from the project generated by the app generator diff --git a/frameworks/Kotlin/vertx-web-kotlin-coroutines/gradle/wrapper/gradle-wrapper.jar b/frameworks/Kotlin/vertx-web-kotlin-coroutines/gradle/wrapper/gradle-wrapper.jar index 943f0cbfa754578e88a3dae77fce6e3dea56edbf..a4b76b9530d66f5e68d973ea569d8e19de379189 100644 GIT binary patch literal 43583 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 yu?e%!_ptzGB|8GrCfu%p?(_ zQccdaaVK$5bz;*rnyK{_SQYM>;aES6Qs^lj9lEs6_J+%nIiuQC*fN;z8md>r_~Mfl zU%p5Dt_YT>gQqfr@`cR!$NWr~+`CZb%dn;WtzrAOI>P_JtsB76PYe*<%H(y>qx-`Kq!X_; z<{RpAqYhE=L1r*M)gNF3B8r(<%8mo*SR2hu zccLRZwGARt)Hlo1euqTyM>^!HK*!Q2P;4UYrysje@;(<|$&%vQekbn|0Ruu_Io(w4#%p6ld2Yp7tlA`Y$cciThP zKzNGIMPXX%&Ud0uQh!uQZz|FB`4KGD?3!ND?wQt6!n*f4EmCoJUh&b?;B{|lxs#F- z31~HQ`SF4x$&v00@(P+j1pAaj5!s`)b2RDBp*PB=2IB>oBF!*6vwr7Dp%zpAx*dPr zb@Zjq^XjN?O4QcZ*O+8>)|HlrR>oD*?WQl5ri3R#2?*W6iJ>>kH%KnnME&TT@ZzrHS$Q%LC?n|e>V+D+8D zYc4)QddFz7I8#}y#Wj6>4P%34dZH~OUDb?uP%-E zwjXM(?Sg~1!|wI(RVuxbu)-rH+O=igSho_pDCw(c6b=P zKk4ATlB?bj9+HHlh<_!&z0rx13K3ZrAR8W)!@Y}o`?a*JJsD+twZIv`W)@Y?Amu_u zz``@-e2X}27$i(2=9rvIu5uTUOVhzwu%mNazS|lZb&PT;XE2|B&W1>=B58#*!~D&) zfVmJGg8UdP*fx(>Cj^?yS^zH#o-$Q-*$SnK(ZVFkw+er=>N^7!)FtP3y~Xxnu^nzY zikgB>Nj0%;WOltWIob|}%lo?_C7<``a5hEkx&1ku$|)i>Rh6@3h*`slY=9U}(Ql_< zaNG*J8vb&@zpdhAvv`?{=zDedJ23TD&Zg__snRAH4eh~^oawdYi6A3w8<Ozh@Kw)#bdktM^GVb zrG08?0bG?|NG+w^&JvD*7LAbjED{_Zkc`3H!My>0u5Q}m!+6VokMLXxl`Mkd=g&Xx z-a>m*#G3SLlhbKB!)tnzfWOBV;u;ftU}S!NdD5+YtOjLg?X}dl>7m^gOpihrf1;PY zvll&>dIuUGs{Qnd- zwIR3oIrct8Va^Tm0t#(bJD7c$Z7DO9*7NnRZorrSm`b`cxz>OIC;jSE3DO8`hX955ui`s%||YQtt2 z5DNA&pG-V+4oI2s*x^>-$6J?p=I>C|9wZF8z;VjR??Icg?1w2v5Me+FgAeGGa8(3S z4vg*$>zC-WIVZtJ7}o9{D-7d>zCe|z#<9>CFve-OPAYsneTb^JH!Enaza#j}^mXy1 z+ULn^10+rWLF6j2>Ya@@Kq?26>AqK{A_| zQKb*~F1>sE*=d?A?W7N2j?L09_7n+HGi{VY;MoTGr_)G9)ot$p!-UY5zZ2Xtbm=t z@dpPSGwgH=QtIcEulQNI>S-#ifbnO5EWkI;$A|pxJd885oM+ zGZ0_0gDvG8q2xebj+fbCHYfAXuZStH2j~|d^sBAzo46(K8n59+T6rzBwK)^rfPT+B zyIFw)9YC-V^rhtK`!3jrhmW-sTmM+tPH+;nwjL#-SjQPUZ53L@A>y*rt(#M(qsiB2 zx6B)dI}6Wlsw%bJ8h|(lhkJVogQZA&n{?Vgs6gNSXzuZpEyu*xySy8ro07QZ7Vk1!3tJphN_5V7qOiyK8p z#@jcDD8nmtYi1^l8ml;AF<#IPK?!pqf9D4moYk>d99Im}Jtwj6c#+A;f)CQ*f-hZ< z=p_T86jog%!p)D&5g9taSwYi&eP z#JuEK%+NULWus;0w32-SYFku#i}d~+{Pkho&^{;RxzP&0!RCm3-9K6`>KZpnzS6?L z^H^V*s!8<>x8bomvD%rh>Zp3>Db%kyin;qtl+jAv8Oo~1g~mqGAC&Qi_wy|xEt2iz zWAJEfTV%cl2Cs<1L&DLRVVH05EDq`pH7Oh7sR`NNkL%wi}8n>IXcO40hp+J+sC!W?!krJf!GJNE8uj zg-y~Ns-<~D?yqbzVRB}G>0A^f0!^N7l=$m0OdZuqAOQqLc zX?AEGr1Ht+inZ-Qiwnl@Z0qukd__a!C*CKuGdy5#nD7VUBM^6OCpxCa2A(X;e0&V4 zM&WR8+wErQ7UIc6LY~Q9x%Sn*Tn>>P`^t&idaOEnOd(Ufw#>NoR^1QdhJ8s`h^|R_ zXX`c5*O~Xdvh%q;7L!_!ohf$NfEBmCde|#uVZvEo>OfEq%+Ns7&_f$OR9xsihRpBb z+cjk8LyDm@U{YN>+r46?nn{7Gh(;WhFw6GAxtcKD+YWV?uge>;+q#Xx4!GpRkVZYu zzsF}1)7$?%s9g9CH=Zs+B%M_)+~*j3L0&Q9u7!|+T`^O{xE6qvAP?XWv9_MrZKdo& z%IyU)$Q95AB4!#hT!_dA>4e@zjOBD*Y=XjtMm)V|+IXzjuM;(l+8aA5#Kaz_$rR6! zj>#&^DidYD$nUY(D$mH`9eb|dtV0b{S>H6FBfq>t5`;OxA4Nn{J(+XihF(stSche7$es&~N$epi&PDM_N`As;*9D^L==2Q7Z2zD+CiU(|+-kL*VG+&9!Yb3LgPy?A zm7Z&^qRG_JIxK7-FBzZI3Q<;{`DIxtc48k> zc|0dmX;Z=W$+)qE)~`yn6MdoJ4co;%!`ddy+FV538Y)j(vg}5*k(WK)KWZ3WaOG!8 z!syGn=s{H$odtpqFrT#JGM*utN7B((abXnpDM6w56nhw}OY}0TiTG1#f*VFZr+^-g zbP10`$LPq_;PvrA1XXlyx2uM^mrjTzX}w{yuLo-cOClE8MMk47T25G8M!9Z5ypOSV zAJUBGEg5L2fY)ZGJb^E34R2zJ?}Vf>{~gB!8=5Z) z9y$>5c)=;o0HeHHSuE4U)#vG&KF|I%-cF6f$~pdYJWk_dD}iOA>iA$O$+4%@>JU08 zS`ep)$XLPJ+n0_i@PkF#ri6T8?ZeAot$6JIYHm&P6EB=BiaNY|aA$W0I+nz*zkz_z zkEru!tj!QUffq%)8y0y`T&`fuus-1p>=^hnBiBqD^hXrPs`PY9tU3m0np~rISY09> z`P3s=-kt_cYcxWd{de@}TwSqg*xVhp;E9zCsnXo6z z?f&Sv^U7n4`xr=mXle94HzOdN!2kB~4=%)u&N!+2;z6UYKUDqi-s6AZ!haB;@&B`? z_TRX0%@suz^TRdCb?!vNJYPY8L_}&07uySH9%W^Tc&1pia6y1q#?*Drf}GjGbPjBS zbOPcUY#*$3sL2x4v_i*Y=N7E$mR}J%|GUI(>WEr+28+V z%v5{#e!UF*6~G&%;l*q*$V?&r$Pp^sE^i-0$+RH3ERUUdQ0>rAq2(2QAbG}$y{de( z>{qD~GGuOk559Y@%$?N^1ApVL_a704>8OD%8Y%8B;FCt%AoPu8*D1 zLB5X>b}Syz81pn;xnB}%0FnwazlWfUV)Z-~rZg6~b z6!9J$EcE&sEbzcy?CI~=boWA&eeIa%z(7SE^qgVLz??1Vbc1*aRvc%Mri)AJaAG!p z$X!_9Ds;Zz)f+;%s&dRcJt2==P{^j3bf0M=nJd&xwUGlUFn?H=2W(*2I2Gdu zv!gYCwM10aeus)`RIZSrCK=&oKaO_Ry~D1B5!y0R=%!i2*KfXGYX&gNv_u+n9wiR5 z*e$Zjju&ODRW3phN925%S(jL+bCHv6rZtc?!*`1TyYXT6%Ju=|X;6D@lq$8T zW{Y|e39ioPez(pBH%k)HzFITXHvnD6hw^lIoUMA;qAJ^CU?top1fo@s7xT13Fvn1H z6JWa-6+FJF#x>~+A;D~;VDs26>^oH0EI`IYT2iagy23?nyJ==i{g4%HrAf1-*v zK1)~@&(KkwR7TL}L(A@C_S0G;-GMDy=MJn2$FP5s<%wC)4jC5PXoxrQBFZ_k0P{{s@sz+gX`-!=T8rcB(=7vW}^K6oLWMmp(rwDh}b zwaGGd>yEy6fHv%jM$yJXo5oMAQ>c9j`**}F?MCry;T@47@r?&sKHgVe$MCqk#Z_3S z1GZI~nOEN*P~+UaFGnj{{Jo@16`(qVNtbU>O0Hf57-P>x8Jikp=`s8xWs^dAJ9lCQ z)GFm+=OV%AMVqVATtN@|vp61VVAHRn87}%PC^RAzJ%JngmZTasWBAWsoAqBU+8L8u z4A&Pe?fmTm0?mK-BL9t+{y7o(7jm+RpOhL9KnY#E&qu^}B6=K_dB}*VlSEiC9fn)+V=J;OnN)Ta5v66ic1rG+dGAJ1 z1%Zb_+!$=tQ~lxQrzv3x#CPb?CekEkA}0MYSgx$Jdd}q8+R=ma$|&1a#)TQ=l$1tQ z=tL9&_^vJ)Pk}EDO-va`UCT1m#Uty1{v^A3P~83_#v^ozH}6*9mIjIr;t3Uv%@VeW zGL6(CwCUp)Jq%G0bIG%?{_*Y#5IHf*5M@wPo6A{$Um++Co$wLC=J1aoG93&T7Ho}P z=mGEPP7GbvoG!uD$k(H3A$Z))+i{Hy?QHdk>3xSBXR0j!11O^mEe9RHmw!pvzv?Ua~2_l2Yh~_!s1qS`|0~0)YsbHSz8!mG)WiJE| z2f($6TQtt6L_f~ApQYQKSb=`053LgrQq7G@98#igV>y#i==-nEjQ!XNu9 z~;mE+gtj4IDDNQJ~JVk5Ux6&LCSFL!y=>79kE9=V}J7tD==Ga+IW zX)r7>VZ9dY=V&}DR))xUoV!u(Z|%3ciQi_2jl}3=$Agc(`RPb z8kEBpvY>1FGQ9W$n>Cq=DIpski};nE)`p3IUw1Oz0|wxll^)4dq3;CCY@RyJgFgc# zKouFh!`?Xuo{IMz^xi-h=StCis_M7yq$u) z?XHvw*HP0VgR+KR6wI)jEMX|ssqYvSf*_3W8zVTQzD?3>H!#>InzpSO)@SC8q*ii- z%%h}_#0{4JG;Jm`4zg};BPTGkYamx$Xo#O~lBirRY)q=5M45n{GCfV7h9qwyu1NxOMoP4)jjZMxmT|IQQh0U7C$EbnMN<3)Kk?fFHYq$d|ICu>KbY_hO zTZM+uKHe(cIZfEqyzyYSUBZa8;Fcut-GN!HSA9ius`ltNebF46ZX_BbZNU}}ZOm{M2&nANL9@0qvih15(|`S~z}m&h!u4x~(%MAO$jHRWNfuxWF#B)E&g3ghSQ9|> z(MFaLQj)NE0lowyjvg8z0#m6FIuKE9lDO~Glg}nSb7`~^&#(Lw{}GVOS>U)m8bF}x zVjbXljBm34Cs-yM6TVusr+3kYFjr28STT3g056y3cH5Tmge~ASxBj z%|yb>$eF;WgrcOZf569sDZOVwoo%8>XO>XQOX1OyN9I-SQgrm;U;+#3OI(zrWyow3 zk==|{lt2xrQ%FIXOTejR>;wv(Pb8u8}BUpx?yd(Abh6? zsoO3VYWkeLnF43&@*#MQ9-i-d0t*xN-UEyNKeyNMHw|A(k(_6QKO=nKMCxD(W(Yop zsRQ)QeL4X3Lxp^L%wzi2-WVSsf61dqliPUM7srDB?Wm6Lzn0&{*}|IsKQW;02(Y&| zaTKv|`U(pSzuvR6Rduu$wzK_W-Y-7>7s?G$)U}&uK;<>vU}^^ns@Z!p+9?St1s)dG zK%y6xkPyyS1$~&6v{kl?Md6gwM|>mt6Upm>oa8RLD^8T{0?HC!Z>;(Bob7el(DV6x zi`I)$&E&ngwFS@bi4^xFLAn`=fzTC;aimE^!cMI2n@Vo%Ae-ne`RF((&5y6xsjjAZ zVguVoQ?Z9uk$2ON;ersE%PU*xGO@T*;j1BO5#TuZKEf(mB7|g7pcEA=nYJ{s3vlbg zd4-DUlD{*6o%Gc^N!Nptgay>j6E5;3psI+C3Q!1ZIbeCubW%w4pq9)MSDyB{HLm|k zxv-{$$A*pS@csolri$Ge<4VZ}e~78JOL-EVyrbxKra^d{?|NnPp86!q>t<&IP07?Z z^>~IK^k#OEKgRH+LjllZXk7iA>2cfH6+(e&9ku5poo~6y{GC5>(bRK7hwjiurqAiZ zg*DmtgY}v83IjE&AbiWgMyFbaRUPZ{lYiz$U^&Zt2YjG<%m((&_JUbZcfJ22(>bi5 z!J?<7AySj0JZ&<-qXX;mcV!f~>G=sB0KnjWca4}vrtunD^1TrpfeS^4dvFr!65knK zZh`d;*VOkPs4*-9kL>$GP0`(M!j~B;#x?Ba~&s6CopvO86oM?-? zOw#dIRc;6A6T?B`Qp%^<U5 z19x(ywSH$_N+Io!6;e?`tWaM$`=Db!gzx|lQ${DG!zb1Zl&|{kX0y6xvO1o z220r<-oaS^^R2pEyY;=Qllqpmue|5yI~D|iI!IGt@iod{Opz@*ml^w2bNs)p`M(Io z|E;;m*Xpjd9l)4G#KaWfV(t8YUn@A;nK^#xgv=LtnArX|vWQVuw3}B${h+frU2>9^ z!l6)!Uo4`5k`<<;E(ido7M6lKTgWezNLq>U*=uz&s=cc$1%>VrAeOoUtA|T6gO4>UNqsdK=NF*8|~*sl&wI=x9-EGiq*aqV!(VVXA57 zw9*o6Ir8Lj1npUXvlevtn(_+^X5rzdR>#(}4YcB9O50q97%rW2me5_L=%ffYPUSRc z!vv?Kv>dH994Qi>U(a<0KF6NH5b16enCp+mw^Hb3Xs1^tThFpz!3QuN#}KBbww`(h z7GO)1olDqy6?T$()R7y%NYx*B0k_2IBiZ14&8|JPFxeMF{vW>HF-Vi3+ZOI=+qP}n zw(+!WcTd~4ZJX1!ZM&y!+uyt=&i!+~d(V%GjH;-NsEEv6nS1TERt|RHh!0>W4+4pp z1-*EzAM~i`+1f(VEHI8So`S`akPfPTfq*`l{Fz`hS%k#JS0cjT2mS0#QLGf=J?1`he3W*;m4)ce8*WFq1sdP=~$5RlH1EdWm|~dCvKOi4*I_96{^95p#B<(n!d?B z=o`0{t+&OMwKcxiBECznJcfH!fL(z3OvmxP#oWd48|mMjpE||zdiTBdWelj8&Qosv zZFp@&UgXuvJw5y=q6*28AtxZzo-UUpkRW%ne+Ylf!V-0+uQXBW=5S1o#6LXNtY5!I z%Rkz#(S8Pjz*P7bqB6L|M#Er{|QLae-Y{KA>`^} z@lPjeX>90X|34S-7}ZVXe{wEei1<{*e8T-Nbj8JmD4iwcE+Hg_zhkPVm#=@b$;)h6 z<<6y`nPa`f3I6`!28d@kdM{uJOgM%`EvlQ5B2bL)Sl=|y@YB3KeOzz=9cUW3clPAU z^sYc}xf9{4Oj?L5MOlYxR{+>w=vJjvbyO5}ptT(o6dR|ygO$)nVCvNGnq(6;bHlBd zl?w-|plD8spjDF03g5ip;W3Z z><0{BCq!Dw;h5~#1BuQilq*TwEu)qy50@+BE4bX28+7erX{BD4H)N+7U`AVEuREE8 z;X?~fyhF-x_sRfHIj~6f(+^@H)D=ngP;mwJjxhQUbUdzk8f94Ab%59-eRIq?ZKrwD z(BFI=)xrUlgu(b|hAysqK<}8bslmNNeD=#JW*}^~Nrswn^xw*nL@Tx!49bfJecV&KC2G4q5a!NSv)06A_5N3Y?veAz;Gv+@U3R% z)~UA8-0LvVE{}8LVDOHzp~2twReqf}ODIyXMM6=W>kL|OHcx9P%+aJGYi_Om)b!xe zF40Vntn0+VP>o<$AtP&JANjXBn7$}C@{+@3I@cqlwR2MdwGhVPxlTIcRVu@Ho-wO` z_~Or~IMG)A_`6-p)KPS@cT9mu9RGA>dVh5wY$NM9-^c@N=hcNaw4ITjm;iWSP^ZX| z)_XpaI61<+La+U&&%2a z0za$)-wZP@mwSELo#3!PGTt$uy0C(nTT@9NX*r3Ctw6J~7A(m#8fE)0RBd`TdKfAT zCf@$MAxjP`O(u9s@c0Fd@|}UQ6qp)O5Q5DPCeE6mSIh|Rj{$cAVIWsA=xPKVKxdhg zLzPZ`3CS+KIO;T}0Ip!fAUaNU>++ZJZRk@I(h<)RsJUhZ&Ru9*!4Ptn;gX^~4E8W^TSR&~3BAZc#HquXn)OW|TJ`CTahk+{qe`5+ixON^zA9IFd8)kc%*!AiLu z>`SFoZ5bW-%7}xZ>gpJcx_hpF$2l+533{gW{a7ce^B9sIdmLrI0)4yivZ^(Vh@-1q zFT!NQK$Iz^xu%|EOK=n>ug;(7J4OnS$;yWmq>A;hsD_0oAbLYhW^1Vdt9>;(JIYjf zdb+&f&D4@4AS?!*XpH>8egQvSVX`36jMd>$+RgI|pEg))^djhGSo&#lhS~9%NuWfX zDDH;3T*GzRT@5=7ibO>N-6_XPBYxno@mD_3I#rDD?iADxX`! zh*v8^i*JEMzyN#bGEBz7;UYXki*Xr(9xXax(_1qVW=Ml)kSuvK$coq2A(5ZGhs_pF z$*w}FbN6+QDseuB9=fdp_MTs)nQf!2SlROQ!gBJBCXD&@-VurqHj0wm@LWX-TDmS= z71M__vAok|@!qgi#H&H%Vg-((ZfxPAL8AI{x|VV!9)ZE}_l>iWk8UPTGHs*?u7RfP z5MC&=c6X;XlUzrz5q?(!eO@~* zoh2I*%J7dF!!_!vXoSIn5o|wj1#_>K*&CIn{qSaRc&iFVxt*^20ngCL;QonIS>I5^ zMw8HXm>W0PGd*}Ko)f|~dDd%;Wu_RWI_d;&2g6R3S63Uzjd7dn%Svu-OKpx*o|N>F zZg=-~qLb~VRLpv`k zWSdfHh@?dp=s_X`{yxOlxE$4iuyS;Z-x!*E6eqmEm*j2bE@=ZI0YZ5%Yj29!5+J$4h{s($nakA`xgbO8w zi=*r}PWz#lTL_DSAu1?f%-2OjD}NHXp4pXOsCW;DS@BC3h-q4_l`<))8WgzkdXg3! zs1WMt32kS2E#L0p_|x+x**TFV=gn`m9BWlzF{b%6j-odf4{7a4y4Uaef@YaeuPhU8 zHBvRqN^;$Jizy+ z=zW{E5<>2gp$pH{M@S*!sJVQU)b*J5*bX4h>5VJve#Q6ga}cQ&iL#=(u+KroWrxa%8&~p{WEUF0il=db;-$=A;&9M{Rq`ouZ5m%BHT6%st%saGsD6)fQgLN}x@d3q>FC;=f%O3Cyg=Ke@Gh`XW za@RajqOE9UB6eE=zhG%|dYS)IW)&y&Id2n7r)6p_)vlRP7NJL(x4UbhlcFXWT8?K=%s7;z?Vjts?y2+r|uk8Wt(DM*73^W%pAkZa1Jd zNoE)8FvQA>Z`eR5Z@Ig6kS5?0h;`Y&OL2D&xnnAUzQz{YSdh0k zB3exx%A2TyI)M*EM6htrxSlep!Kk(P(VP`$p0G~f$smld6W1r_Z+o?=IB@^weq>5VYsYZZR@` z&XJFxd5{|KPZmVOSxc@^%71C@;z}}WhbF9p!%yLj3j%YOlPL5s>7I3vj25 z@xmf=*z%Wb4;Va6SDk9cv|r*lhZ`(y_*M@>q;wrn)oQx%B(2A$9(74>;$zmQ!4fN; z>XurIk-7@wZys<+7XL@0Fhe-f%*=(weaQEdR9Eh6>Kl-EcI({qoZqyzziGwpg-GM#251sK_ z=3|kitS!j%;fpc@oWn65SEL73^N&t>Ix37xgs= zYG%eQDJc|rqHFia0!_sm7`@lvcv)gfy(+KXA@E{3t1DaZ$DijWAcA)E0@X?2ziJ{v z&KOYZ|DdkM{}t+@{@*6ge}m%xfjIxi%qh`=^2Rwz@w0cCvZ&Tc#UmCDbVwABrON^x zEBK43FO@weA8s7zggCOWhMvGGE`baZ62cC)VHyy!5Zbt%ieH+XN|OLbAFPZWyC6)p z4P3%8sq9HdS3=ih^0OOlqTPbKuzQ?lBEI{w^ReUO{V?@`ARsL|S*%yOS=Z%sF)>-y z(LAQdhgAcuF6LQjRYfdbD1g4o%tV4EiK&ElLB&^VZHbrV1K>tHTO{#XTo>)2UMm`2 z^t4s;vnMQgf-njU-RVBRw0P0-m#d-u`(kq7NL&2T)TjI_@iKuPAK-@oH(J8?%(e!0Ir$yG32@CGUPn5w4)+9@8c&pGx z+K3GKESI4*`tYlmMHt@br;jBWTei&(a=iYslc^c#RU3Q&sYp zSG){)V<(g7+8W!Wxeb5zJb4XE{I|&Y4UrFWr%LHkdQ;~XU zgy^dH-Z3lmY+0G~?DrC_S4@=>0oM8Isw%g(id10gWkoz2Q%7W$bFk@mIzTCcIB(K8 zc<5h&ZzCdT=9n-D>&a8vl+=ZF*`uTvQviG_bLde*k>{^)&0o*b05x$MO3gVLUx`xZ z43j+>!u?XV)Yp@MmG%Y`+COH2?nQcMrQ%k~6#O%PeD_WvFO~Kct za4XoCM_X!c5vhRkIdV=xUB3xI2NNStK*8_Zl!cFjOvp-AY=D;5{uXj}GV{LK1~IE2 z|KffUiBaStRr;10R~K2VVtf{TzM7FaPm;Y(zQjILn+tIPSrJh&EMf6evaBKIvi42-WYU9Vhj~3< zZSM-B;E`g_o8_XTM9IzEL=9Lb^SPhe(f(-`Yh=X6O7+6ALXnTcUFpI>ekl6v)ZQeNCg2 z^H|{SKXHU*%nBQ@I3It0m^h+6tvI@FS=MYS$ZpBaG7j#V@P2ZuYySbp@hA# ze(kc;P4i_-_UDP?%<6>%tTRih6VBgScKU^BV6Aoeg6Uh(W^#J^V$Xo^4#Ekp ztqQVK^g9gKMTHvV7nb64UU7p~!B?>Y0oFH5T7#BSW#YfSB@5PtE~#SCCg3p^o=NkMk$<8- z6PT*yIKGrvne7+y3}_!AC8NNeI?iTY(&nakN>>U-zT0wzZf-RuyZk^X9H-DT_*wk= z;&0}6LsGtfVa1q)CEUPlx#(ED@-?H<1_FrHU#z5^P3lEB|qsxEyn%FOpjx z3S?~gvoXy~L(Q{Jh6*i~=f%9kM1>RGjBzQh_SaIDfSU_9!<>*Pm>l)cJD@wlyxpBV z4Fmhc2q=R_wHCEK69<*wG%}mgD1=FHi4h!98B-*vMu4ZGW~%IrYSLGU{^TuseqVgV zLP<%wirIL`VLyJv9XG_p8w@Q4HzNt-o;U@Au{7%Ji;53!7V8Rv0^Lu^Vf*sL>R(;c zQG_ZuFl)Mh-xEIkGu}?_(HwkB2jS;HdPLSxVU&Jxy9*XRG~^HY(f0g8Q}iqnVmgjI zfd=``2&8GsycjR?M%(zMjn;tn9agcq;&rR!Hp z$B*gzHsQ~aXw8c|a(L^LW(|`yGc!qOnV(ZjU_Q-4z1&0;jG&vAKuNG=F|H?@m5^N@ zq{E!1n;)kNTJ>|Hb2ODt-7U~-MOIFo%9I)_@7fnX+eMMNh>)V$IXesJpBn|uo8f~#aOFytCT zf9&%MCLf8mp4kwHTcojWmM3LU=#|{3L>E}SKwOd?%{HogCZ_Z1BSA}P#O(%H$;z7XyJ^sjGX;j5 zrzp>|Ud;*&VAU3x#f{CKwY7Vc{%TKKqmB@oTHA9;>?!nvMA;8+Jh=cambHz#J18x~ zs!dF>$*AnsQ{{82r5Aw&^7eRCdvcgyxH?*DV5(I$qXh^zS>us*I66_MbL8y4d3ULj z{S(ipo+T3Ag!+5`NU2sc+@*m{_X|&p#O-SAqF&g_n7ObB82~$p%fXA5GLHMC+#qqL zdt`sJC&6C2)=juQ_!NeD>U8lDVpAOkW*khf7MCcs$A(wiIl#B9HM%~GtQ^}yBPjT@ z+E=|A!Z?A(rwzZ;T}o6pOVqHzTr*i;Wrc%&36kc@jXq~+w8kVrs;%=IFdACoLAcCAmhFNpbP8;s`zG|HC2Gv?I~w4ITy=g$`0qMQdkijLSOtX6xW%Z9Nw<;M- zMN`c7=$QxN00DiSjbVt9Mi6-pjv*j(_8PyV-il8Q-&TwBwH1gz1uoxs6~uU}PrgWB zIAE_I-a1EqlIaGQNbcp@iI8W1sm9fBBNOk(k&iLBe%MCo#?xI$%ZmGA?=)M9D=0t7 zc)Q0LnI)kCy{`jCGy9lYX%mUsDWwsY`;jE(;Us@gmWPqjmXL+Hu#^;k%eT>{nMtzj zsV`Iy6leTA8-PndszF;N^X@CJrTw5IIm!GPeu)H2#FQitR{1p;MasQVAG3*+=9FYK zw*k!HT(YQorfQj+1*mCV458(T5=fH`um$gS38hw(OqVMyunQ;rW5aPbF##A3fGH6h z@W)i9Uff?qz`YbK4c}JzQpuxuE3pcQO)%xBRZp{zJ^-*|oryTxJ-rR+MXJ)!f=+pp z10H|DdGd2exhi+hftcYbM0_}C0ZI-2vh+$fU1acsB-YXid7O|=9L!3e@$H*6?G*Zp z%qFB(sgl=FcC=E4CYGp4CN>=M8#5r!RU!u+FJVlH6=gI5xHVD&k;Ta*M28BsxfMV~ zLz+@6TxnfLhF@5=yQo^1&S}cmTN@m!7*c6z;}~*!hNBjuE>NLVl2EwN!F+)0$R1S! zR|lF%n!9fkZ@gPW|x|B={V6x3`=jS*$Pu0+5OWf?wnIy>Y1MbbGSncpKO0qE(qO=ts z!~@&!N`10S593pVQu4FzpOh!tvg}p%zCU(aV5=~K#bKi zHdJ1>tQSrhW%KOky;iW+O_n;`l9~omqM%sdxdLtI`TrJzN6BQz+7xOl*rM>xVI2~# z)7FJ^Dc{DC<%~VS?@WXzuOG$YPLC;>#vUJ^MmtbSL`_yXtNKa$Hk+l-c!aC7gn(Cg ze?YPYZ(2Jw{SF6MiO5(%_pTo7j@&DHNW`|lD`~{iH+_eSTS&OC*2WTT*a`?|9w1dh zh1nh@$a}T#WE5$7Od~NvSEU)T(W$p$s5fe^GpG+7fdJ9=enRT9$wEk+ZaB>G3$KQO zgq?-rZZnIv!p#>Ty~}c*Lb_jxJg$eGM*XwHUwuQ|o^}b3^T6Bxx{!?va8aC@-xK*H ztJBFvFfsSWu89%@b^l3-B~O!CXs)I6Y}y#0C0U0R0WG zybjroj$io0j}3%P7zADXOwHwafT#uu*zfM!oD$6aJx7+WL%t-@6^rD_a_M?S^>c;z zMK580bZXo1f*L$CuMeM4Mp!;P@}b~$cd(s5*q~FP+NHSq;nw3fbWyH)i2)-;gQl{S zZO!T}A}fC}vUdskGSq&{`oxt~0i?0xhr6I47_tBc`fqaSrMOzR4>0H^;A zF)hX1nfHs)%Zb-(YGX;=#2R6C{BG;k=?FfP?9{_uFLri~-~AJ;jw({4MU7e*d)?P@ zXX*GkNY9ItFjhwgAIWq7Y!ksbMzfqpG)IrqKx9q{zu%Mdl+{Dis#p9q`02pr1LG8R z@As?eG!>IoROgS!@J*to<27coFc1zpkh?w=)h9CbYe%^Q!Ui46Y*HO0mr% zEff-*$ndMNw}H2a5@BsGj5oFfd!T(F&0$<{GO!Qdd?McKkorh=5{EIjDTHU`So>8V zBA-fqVLb2;u7UhDV1xMI?y>fe3~4urv3%PX)lDw+HYa;HFkaLqi4c~VtCm&Ca+9C~ zge+67hp#R9`+Euq59WhHX&7~RlXn=--m8$iZ~~1C8cv^2(qO#X0?vl91gzUKBeR1J z^p4!!&7)3#@@X&2aF2-)1Ffcc^F8r|RtdL2X%HgN&XU-KH2SLCbpw?J5xJ*!F-ypZ zMG%AJ!Pr&}`LW?E!K~=(NJxuSVTRCGJ$2a*Ao=uUDSys!OFYu!Vs2IT;xQ6EubLIl z+?+nMGeQQhh~??0!s4iQ#gm3!BpMpnY?04kK375e((Uc7B3RMj;wE?BCoQGu=UlZt!EZ1Q*auI)dj3Jj{Ujgt zW5hd~-HWBLI_3HuO) zNrb^XzPsTIb=*a69wAAA3J6AAZZ1VsYbIG}a`=d6?PjM)3EPaDpW2YP$|GrBX{q*! z$KBHNif)OKMBCFP5>!1d=DK>8u+Upm-{hj5o|Wn$vh1&K!lVfDB&47lw$tJ?d5|=B z^(_9=(1T3Fte)z^>|3**n}mIX;mMN5v2F#l(q*CvU{Ga`@VMp#%rQkDBy7kYbmb-q z<5!4iuB#Q_lLZ8}h|hPODI^U6`gzLJre9u3k3c#%86IKI*^H-@I48Bi*@avYm4v!n0+v zWu{M{&F8#p9cx+gF0yTB_<2QUrjMPo9*7^-uP#~gGW~y3nfPAoV%amgr>PSyVAd@l)}8#X zR5zV6t*uKJZL}?NYvPVK6J0v4iVpwiN|>+t3aYiZSp;m0!(1`bHO}TEtWR1tY%BPB z(W!0DmXbZAsT$iC13p4f>u*ZAy@JoLAkJhzFf1#4;#1deO8#8d&89}en&z!W&A3++^1(;>0SB1*54d@y&9Pn;^IAf3GiXbfT`_>{R+Xv; zQvgL>+0#8-laO!j#-WB~(I>l0NCMt_;@Gp_f0#^c)t?&#Xh1-7RR0@zPyBz!U#0Av zT?}n({(p?p7!4S2ZBw)#KdCG)uPnZe+U|0{BW!m)9 zi_9$F?m<`2!`JNFv+w8MK_K)qJ^aO@7-Ig>cM4-r0bi=>?B_2mFNJ}aE3<+QCzRr*NA!QjHw# z`1OsvcoD0?%jq{*7b!l|L1+Tw0TTAM4XMq7*ntc-Ived>Sj_ZtS|uVdpfg1_I9knY z2{GM_j5sDC7(W&}#s{jqbybqJWyn?{PW*&cQIU|*v8YGOKKlGl@?c#TCnmnAkAzV- zmK={|1G90zz=YUvC}+fMqts0d4vgA%t6Jhjv?d;(Z}(Ep8fTZfHA9``fdUHkA+z3+ zhh{ohP%Bj?T~{i0sYCQ}uC#5BwN`skI7`|c%kqkyWIQ;!ysvA8H`b-t()n6>GJj6xlYDu~8qX{AFo$Cm3d|XFL=4uvc?Keb zzb0ZmMoXca6Mob>JqkNuoP>B2Z>D`Q(TvrG6m`j}-1rGP!g|qoL=$FVQYxJQjFn33lODt3Wb1j8VR zlR++vIT6^DtYxAv_hxupbLLN3e0%A%a+hWTKDV3!Fjr^cWJ{scsAdfhpI)`Bms^M6 zQG$waKgFr=c|p9Piug=fcJvZ1ThMnNhQvBAg-8~b1?6wL*WyqXhtj^g(Ke}mEfZVM zJuLNTUVh#WsE*a6uqiz`b#9ZYg3+2%=C(6AvZGc=u&<6??!slB1a9K)=VL zY9EL^mfyKnD zSJyYBc_>G;5RRnrNgzJz#Rkn3S1`mZgO`(r5;Hw6MveN(URf_XS-r58Cn80K)ArH4 z#Rrd~LG1W&@ttw85cjp8xV&>$b%nSXH_*W}7Ch2pg$$c0BdEo-HWRTZcxngIBJad> z;C>b{jIXjb_9Jis?NZJsdm^EG}e*pR&DAy0EaSGi3XWTa(>C%tz1n$u?5Fb z1qtl?;_yjYo)(gB^iQq?=jusF%kywm?CJP~zEHi0NbZ);$(H$w(Hy@{i>$wcVRD_X|w-~(0Z9BJyh zhNh;+eQ9BEIs;tPz%jSVnfCP!3L&9YtEP;svoj_bNzeGSQIAjd zBss@A;)R^WAu-37RQrM%{DfBNRx>v!G31Z}8-El9IOJlb_MSoMu2}GDYycNaf>uny z+8xykD-7ONCM!APry_Lw6-yT>5!tR}W;W`C)1>pxSs5o1z#j7%m=&=7O4hz+Lsqm` z*>{+xsabZPr&X=}G@obTb{nPTkccJX8w3CG7X+1+t{JcMabv~UNv+G?txRqXib~c^Mo}`q{$`;EBNJ;#F*{gvS12kV?AZ%O0SFB$^ zn+}!HbmEj}w{Vq(G)OGAzH}R~kS^;(-s&=ectz8vN!_)Yl$$U@HNTI-pV`LSj7Opu zTZ5zZ)-S_{GcEQPIQXLQ#oMS`HPu{`SQiAZ)m1at*Hy%3xma|>o`h%E%8BEbi9p0r zVjcsh<{NBKQ4eKlXU|}@XJ#@uQw*$4BxKn6#W~I4T<^f99~(=}a`&3(ur8R9t+|AQ zWkQx7l}wa48-jO@ft2h+7qn%SJtL%~890FG0s5g*kNbL3I&@brh&f6)TlM`K^(bhr zJWM6N6x3flOw$@|C@kPi7yP&SP?bzP-E|HSXQXG>7gk|R9BTj`e=4de9C6+H7H7n# z#GJeVs1mtHhLDmVO?LkYRQc`DVOJ_vdl8VUihO-j#t=0T3%Fc1f9F73ufJz*adn*p zc%&vi(4NqHu^R>sAT_0EDjVR8bc%wTz#$;%NU-kbDyL_dg0%TFafZwZ?5KZpcuaO54Z9hX zD$u>q!-9`U6-D`E#`W~fIfiIF5_m6{fvM)b1NG3xf4Auw;Go~Fu7cth#DlUn{@~yu z=B;RT*dp?bO}o%4x7k9v{r=Y@^YQ^UUm(Qmliw8brO^=NP+UOohLYiaEB3^DB56&V zK?4jV61B|1Uj_5fBKW;8LdwOFZKWp)g{B%7g1~DgO&N& z#lisxf?R~Z@?3E$Mms$$JK8oe@X`5m98V*aV6Ua}8Xs2#A!{x?IP|N(%nxsH?^c{& z@vY&R1QmQs83BW28qAmJfS7MYi=h(YK??@EhjL-t*5W!p z^gYX!Q6-vBqcv~ruw@oMaU&qp0Fb(dbVzm5xJN%0o_^@fWq$oa3X?9s%+b)x4w-q5Koe(@j6Ez7V@~NRFvd zfBH~)U5!ix3isg`6be__wBJp=1@yfsCMw1C@y+9WYD9_C%{Q~7^0AF2KFryfLlUP# zwrtJEcH)jm48!6tUcxiurAMaiD04C&tPe6DI0#aoqz#Bt0_7_*X*TsF7u*zv(iEfA z;$@?XVu~oX#1YXtceQL{dSneL&*nDug^OW$DSLF0M1Im|sSX8R26&)<0Fbh^*l6!5wfSu8MpMoh=2l z^^0Sr$UpZp*9oqa23fcCfm7`ya2<4wzJ`Axt7e4jJrRFVf?nY~2&tRL* zd;6_njcz01c>$IvN=?K}9ie%Z(BO@JG2J}fT#BJQ+f5LFSgup7i!xWRKw6)iITjZU z%l6hPZia>R!`aZjwCp}I zg)%20;}f+&@t;(%5;RHL>K_&7MH^S+7<|(SZH!u zznW|jz$uA`P9@ZWtJgv$EFp>)K&Gt+4C6#*khZQXS*S~6N%JDT$r`aJDs9|uXWdbg zBwho$phWx}x!qy8&}6y5Vr$G{yGSE*r$^r{}pw zVTZKvikRZ`J_IJrjc=X1uw?estdwm&bEahku&D04HD+0Bm~q#YGS6gp!KLf$A{%Qd z&&yX@Hp>~(wU{|(#U&Bf92+1i&Q*-S+=y=3pSZy$#8Uc$#7oiJUuO{cE6=tsPhwPe| zxQpK>`Dbka`V)$}e6_OXKLB%i76~4N*zA?X+PrhH<&)}prET;kel24kW%+9))G^JI zsq7L{P}^#QsZViX%KgxBvEugr>ZmFqe^oAg?{EI=&_O#e)F3V#rc z8$4}0Zr19qd3tE4#$3_f=Bbx9oV6VO!d3(R===i-7p=Vj`520w0D3W6lQfY48}!D* z&)lZMG;~er2qBoI2gsX+Ts-hnpS~NYRDtPd^FPzn!^&yxRy#CSz(b&E*tL|jIkq|l zf%>)7Dtu>jCf`-7R#*GhGn4FkYf;B$+9IxmqH|lf6$4irg{0ept__%)V*R_OK=T06 zyT_m-o@Kp6U{l5h>W1hGq*X#8*y@<;vsOFqEjTQXFEotR+{3}ODDnj;o0@!bB5x=N z394FojuGOtVKBlVRLtHp%EJv_G5q=AgF)SKyRN5=cGBjDWv4LDn$IL`*=~J7u&Dy5 zrMc83y+w^F&{?X(KOOAl-sWZDb{9X9#jrQtmrEXD?;h-}SYT7yM(X_6qksM=K_a;Z z3u0qT0TtaNvDER_8x*rxXw&C^|h{P1qxK|@pS7vdlZ#P z7PdB7MmC2}%sdzAxt>;WM1s0??`1983O4nFK|hVAbHcZ3x{PzytQLkCVk7hA!Lo` zEJH?4qw|}WH{dc4z%aB=0XqsFW?^p=X}4xnCJXK%c#ItOSjdSO`UXJyuc8bh^Cf}8 z@Ht|vXd^6{Fgai8*tmyRGmD_s_nv~r^Fy7j`Bu`6=G)5H$i7Q7lvQnmea&TGvJp9a|qOrUymZ$6G|Ly z#zOCg++$3iB$!6!>215A4!iryregKuUT344X)jQb3|9qY>c0LO{6Vby05n~VFzd?q zgGZv&FGlkiH*`fTurp>B8v&nSxNz)=5IF$=@rgND4d`!AaaX;_lK~)-U8la_Wa8i?NJC@BURO*sUW)E9oyv3RG^YGfN%BmxzjlT)bp*$<| zX3tt?EAy<&K+bhIuMs-g#=d1}N_?isY)6Ay$mDOKRh z4v1asEGWoAp=srraLW^h&_Uw|6O+r;wns=uwYm=JN4Q!quD8SQRSeEcGh|Eb5Jg8m zOT}u;N|x@aq)=&;wufCc^#)5U^VcZw;d_wwaoh9$p@Xrc{DD6GZUqZ ziC6OT^zSq@-lhbgR8B+e;7_Giv;DK5gn^$bs<6~SUadiosfewWDJu`XsBfOd1|p=q zE>m=zF}!lObA%ePey~gqU8S6h-^J2Y?>7)L2+%8kV}Gp=h`Xm_}rlm)SyUS=`=S7msKu zC|T!gPiI1rWGb1z$Md?0YJQ;%>uPLOXf1Z>N~`~JHJ!^@D5kSXQ4ugnFZ>^`zH8CAiZmp z6Ms|#2gcGsQ{{u7+Nb9sA?U>(0e$5V1|WVwY`Kn)rsnnZ4=1u=7u!4WexZD^IQ1Jk zfF#NLe>W$3m&C^ULjdw+5|)-BSHwpegdyt9NYC{3@QtMfd8GrIWDu`gd0nv-3LpGCh@wgBaG z176tikL!_NXM+Bv#7q^cyn9$XSeZR6#!B4JE@GVH zoobHZN_*RF#@_SVYKkQ_igme-Y5U}cV(hkR#k1c{bQNMji zU7aE`?dHyx=1`kOYZo_8U7?3-7vHOp`Qe%Z*i+FX!s?6huNp0iCEW-Z7E&jRWmUW_ z67j>)Ew!yq)hhG4o?^z}HWH-e=es#xJUhDRc4B51M4~E-l5VZ!&zQq`gWe`?}#b~7w1LH4Xa-UCT5LXkXQWheBa2YJYbyQ zl1pXR%b(KCXMO0OsXgl0P0Og<{(@&z1aokU-Pq`eQq*JYgt8xdFQ6S z6Z3IFSua8W&M#`~*L#r>Jfd6*BzJ?JFdBR#bDv$_0N!_5vnmo@!>vULcDm`MFU823 zpG9pqjqz^FE5zMDoGqhs5OMmC{Y3iVcl>F}5Rs24Y5B^mYQ;1T&ks@pIApHOdrzXF z-SdX}Hf{X;TaSxG_T$0~#RhqKISGKNK47}0*x&nRIPtmdwxc&QT3$8&!3fWu1eZ_P zJveQj^hJL#Sn!*4k`3}(d(aasl&7G0j0-*_2xtAnoX1@9+h zO#c>YQg60Z;o{Bi=3i7S`Ic+ZE>K{(u|#)9y}q*j8uKQ1^>+(BI}m%1v3$=4ojGBc zm+o1*!T&b}-lVvZqIUBc8V}QyFEgm#oyIuC{8WqUNV{Toz`oxhYpP!_p2oHHh5P@iB*NVo~2=GQm+8Yrkm2Xjc_VyHg1c0>+o~@>*Qzo zHVBJS>$$}$_4EniTI;b1WShX<5-p#TPB&!;lP!lBVBbLOOxh6FuYloD%m;n{r|;MU3!q4AVkua~fieeWu2 zQAQ$ue(IklX6+V;F1vCu-&V?I3d42FgWgsb_e^29ol}HYft?{SLf>DrmOp9o!t>I^ zY7fBCk+E8n_|apgM|-;^=#B?6RnFKlN`oR)`e$+;D=yO-(U^jV;rft^G_zl`n7qnM zL z*-Y4Phq+ZI1$j$F-f;`CD#|`-T~OM5Q>x}a>B~Gb3-+9i>Lfr|Ca6S^8g*{*?_5!x zH_N!SoRP=gX1?)q%>QTY!r77e2j9W(I!uAz{T`NdNmPBBUzi2{`XMB^zJGGwFWeA9 z{fk33#*9SO0)DjROug+(M)I-pKA!CX;IY(#gE!UxXVsa)X!UftIN98{pt#4MJHOhY zM$_l}-TJlxY?LS6Nuz1T<44m<4i^8k@D$zuCPrkmz@sdv+{ciyFJG2Zwy&%c7;atIeTdh!a(R^QXnu1Oq1b42*OQFWnyQ zWeQrdvP|w_idy53Wa<{QH^lFmEd+VlJkyiC>6B#s)F;w-{c;aKIm;Kp50HnA-o3lY z9B~F$gJ@yYE#g#X&3ADx&tO+P_@mnQTz9gv30_sTsaGXkfNYXY{$(>*PEN3QL>I!k zp)KibPhrfX3%Z$H6SY`rXGYS~143wZrG2;=FLj50+VM6soI~up_>fU(2Wl@{BRsMi zO%sL3x?2l1cXTF)k&moNsHfQrQ+wu(gBt{sk#CU=UhrvJIncy@tJX5klLjgMn>~h= zg|FR&;@eh|C7`>s_9c~0-{IAPV){l|Ts`i=)AW;d9&KPc3fMeoTS%8@V~D8*h;&(^>yjT84MM}=%#LS7shLAuuj(0VAYoozhWjq z4LEr?wUe2^WGwdTIgWBkDUJa>YP@5d9^Rs$kCXmMRxuF*YMVrn?0NFyPl}>`&dqZb z<5eqR=ZG3>n2{6v6BvJ`YBZeeTtB88TAY(x0a58EWyuf>+^|x8Qa6wA|1Nb_p|nA zWWa}|z8a)--Wj`LqyFk_a3gN2>5{Rl_wbW?#by7&i*^hRknK%jwIH6=dQ8*-_{*x0j^DUfMX0`|K@6C<|1cgZ~D(e5vBFFm;HTZF(!vT8=T$K+|F)x3kqzBV4-=p1V(lzi(s7jdu0>LD#N=$Lk#3HkG!a zIF<7>%B7sRNzJ66KrFV76J<2bdYhxll0y2^_rdG=I%AgW4~)1Nvz=$1UkE^J%BxLo z+lUci`UcU062os*=`-j4IfSQA{w@y|3}Vk?i;&SSdh8n+$iHA#%ERL{;EpXl6u&8@ zzg}?hkEOUOJt?ZL=pWZFJ19mI1@P=$U5*Im1e_8Z${JsM>Ov?nh8Z zP5QvI!{Jy@&BP48%P2{Jr_VgzW;P@7)M9n|lDT|Ep#}7C$&ud&6>C^5ZiwKIg2McPU(4jhM!BD@@L(Gd*Nu$ji(ljZ<{FIeW_1Mmf;76{LU z-ywN~=uNN)Xi6$<12A9y)K%X|(W0p|&>>4OXB?IiYr||WKDOJPxiSe01NSV-h24^L z_>m$;|C+q!Mj**-qQ$L-*++en(g|hw;M!^%_h-iDjFHLo-n3JpB;p?+o2;`*jpvJU zLY^lt)Un4joij^^)O(CKs@7E%*!w>!HA4Q?0}oBJ7Nr8NQ7QmY^4~jvf0-`%waOLn zdNjAPaC0_7c|RVhw)+71NWjRi!y>C+Bl;Z`NiL^zn2*0kmj5gyhCLCxts*cWCdRI| zjsd=sT5BVJc^$GxP~YF$-U{-?kW6r@^vHXB%{CqYzU@1>dzf#3SYedJG-Rm6^RB7s zGM5PR(yKPKR)>?~vpUIeTP7A1sc8-knnJk*9)3t^e%izbdm>Y=W{$wm(cy1RB-19i za#828DMBY+ps#7Y8^6t)=Ea@%Nkt)O6JCx|ybC;Ap}Z@Zw~*}3P>MZLPb4Enxz9Wf zssobT^(R@KuShj8>@!1M7tm|2%-pYYDxz-5`rCbaTCG5{;Uxm z*g=+H1X8{NUvFGzz~wXa%Eo};I;~`37*WrRU&K0dPSB$yk(Z*@K&+mFal^?c zurbqB-+|Kb5|sznT;?Pj!+kgFY1#Dr;_%A(GIQC{3ct|{*Bji%FNa6c-thbpBkA;U zURV!Dr&X{0J}iht#-Qp2=xzuh(fM>zRoiGrYl5ttw2#r34gC41CCOC31m~^UPTK@s z6;A@)7O7_%C)>bnAXerYuAHdE93>j2N}H${zEc6&SbZ|-fiG*-qtGuy-qDelH(|u$ zorf8_T6Zqe#Ub!+e3oSyrskt_HyW_^5lrWt#30l)tHk|j$@YyEkXUOV;6B51L;M@=NIWZXU;GrAa(LGxO%|im%7F<-6N;en0Cr zLH>l*y?pMwt`1*cH~LdBPFY_l;~`N!Clyfr;7w<^X;&(ZiVdF1S5e(+Q%60zgh)s4 zn2yj$+mE=miVERP(g8}G4<85^-5f@qxh2ec?n+$A_`?qN=iyT1?U@t?V6DM~BIlBB z>u~eXm-aE>R0sQy!-I4xtCNi!!qh?R1!kKf6BoH2GG{L4%PAz0{Sh6xpuyI%*~u)s z%rLuFl)uQUCBQAtMyN;%)zFMx4loh7uTfKeB2Xif`lN?2gq6NhWhfz0u5WP9J>=V2 zo{mLtSy&BA!mSzs&CrKWq^y40JF5a&GSXIi2= z{EYb59J4}VwikL4P=>+mc6{($FNE@e=VUwG+KV21;<@lrN`mnz5jYGASyvz7BOG_6(p^eTxD-4O#lROgon;R35=|nj#eHIfJBYPWG>H>`dHKCDZ3`R{-?HO0mE~(5_WYcFmp8sU?wr*UkAQiNDGc6T zA%}GOLXlOWqL?WwfHO8MB#8M8*~Y*gz;1rWWoVSXP&IbKxbQ8+s%4Jnt?kDsq7btI zCDr0PZ)b;B%!lu&CT#RJzm{l{2fq|BcY85`w~3LSK<><@(2EdzFLt9Y_`;WXL6x`0 zDoQ?=?I@Hbr;*VVll1Gmd8*%tiXggMK81a+T(5Gx6;eNb8=uYn z5BG-0g>pP21NPn>$ntBh>`*})Fl|38oC^9Qz>~MAazH%3Q~Qb!ALMf$srexgPZ2@&c~+hxRi1;}+)-06)!#Mq<6GhP z-Q?qmgo${aFBApb5p}$1OJKTClfi8%PpnczyVKkoHw7Ml9e7ikrF0d~UB}i3vizos zXW4DN$SiEV9{faLt5bHy2a>33K%7Td-n5C*N;f&ZqAg#2hIqEb(y<&f4u5BWJ>2^4 z414GosL=Aom#m&=x_v<0-fp1r%oVJ{T-(xnomNJ(Dryv zh?vj+%=II_nV+@NR+(!fZZVM&(W6{6%9cm+o+Z6}KqzLw{(>E86uA1`_K$HqINlb1 zKelh3-jr2I9V?ych`{hta9wQ2c9=MM`2cC{m6^MhlL2{DLv7C^j z$xXBCnDl_;l|bPGMX@*tV)B!c|4oZyftUlP*?$YU9C_eAsuVHJ58?)zpbr30P*C`T z7y#ao`uE-SOG(Pi+`$=e^mle~)pRrdwL5)N;o{gpW21of(QE#U6w%*C~`v-z0QqBML!!5EeYA5IQB0 z^l01c;L6E(iytN!LhL}wfwP7W9PNAkb+)Cst?qg#$n;z41O4&v+8-zPs+XNb-q zIeeBCh#ivnFLUCwfS;p{LC0O7tm+Sf9Jn)~b%uwP{%69;QC)Ok0t%*a5M+=;y8j=v z#!*pp$9@!x;UMIs4~hP#pnfVc!%-D<+wsG@R2+J&%73lK|2G!EQC)O05TCV=&3g)C!lT=czLpZ@Sa%TYuoE?v8T8`V;e$#Zf2_Nj6nvBgh1)2 GZ~q4|mN%#X literal 61574 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 ScNgau(U?ep-K_E5zy1%ZQTdPn diff --git a/frameworks/Kotlin/vertx-web-kotlin-coroutines/gradle/wrapper/gradle-wrapper.properties b/frameworks/Kotlin/vertx-web-kotlin-coroutines/gradle/wrapper/gradle-wrapper.properties index 2b22d057a07..79eb9d003fe 100644 --- a/frameworks/Kotlin/vertx-web-kotlin-coroutines/gradle/wrapper/gradle-wrapper.properties +++ b/frameworks/Kotlin/vertx-web-kotlin-coroutines/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,7 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.6-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-all.zip networkTimeout=10000 +validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/frameworks/Kotlin/vertx-web-kotlin-coroutines/gradlew b/frameworks/Kotlin/vertx-web-kotlin-coroutines/gradlew old mode 100644 new mode 100755 index 65dcd68d65c..f5feea6d6b1 --- a/frameworks/Kotlin/vertx-web-kotlin-coroutines/gradlew +++ b/frameworks/Kotlin/vertx-web-kotlin-coroutines/gradlew @@ -15,6 +15,8 @@ # See the License for the specific language governing permissions and # limitations under the License. # +# SPDX-License-Identifier: Apache-2.0 +# ############################################################################## # @@ -55,7 +57,7 @@ # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template -# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. @@ -83,10 +85,9 @@ done # This is normally unused # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} -APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit - -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' +# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) +APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s +' "$PWD" ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum @@ -133,10 +134,13 @@ location of your Java installation." fi else JAVACMD=java - which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + if ! command -v java >/dev/null 2>&1 + then + die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." + fi fi # Increase the maximum file descriptors if we can. @@ -144,7 +148,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC3045 + # shellcheck disable=SC2039,SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac @@ -152,7 +156,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then '' | soft) :;; #( *) # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC3045 + # shellcheck disable=SC2039,SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac @@ -197,11 +201,15 @@ if "$cygwin" || "$msys" ; then done fi -# Collect all arguments for the java command; -# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of -# shell script including quotes and variable substitutions, so put them in -# double quotes to make sure that they get re-expanded; and -# * put everything else in single quotes, so that it's not re-expanded. + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Collect all arguments for the java command: +# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# and any embedded shellness will be escaped. +# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be +# treated as '${Hostname}' itself on the command line. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ diff --git a/frameworks/Kotlin/vertx-web-kotlin-coroutines/gradlew.bat b/frameworks/Kotlin/vertx-web-kotlin-coroutines/gradlew.bat index 93e3f59f135..9d21a21834d 100644 --- a/frameworks/Kotlin/vertx-web-kotlin-coroutines/gradlew.bat +++ b/frameworks/Kotlin/vertx-web-kotlin-coroutines/gradlew.bat @@ -13,6 +13,8 @@ @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem +@rem SPDX-License-Identifier: Apache-2.0 +@rem @if "%DEBUG%"=="" @echo off @rem ########################################################################## @@ -43,11 +45,11 @@ set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 if %ERRORLEVEL% equ 0 goto execute -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. +echo. 1>&2 +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 goto fail @@ -57,11 +59,11 @@ set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto execute -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. +echo. 1>&2 +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 goto fail diff --git a/frameworks/Kotlin/vertx-web-kotlin-coroutines/vertx-web-kotlin-coroutines-postgres.dockerfile b/frameworks/Kotlin/vertx-web-kotlin-coroutines/vertx-web-kotlin-coroutines-postgres.dockerfile index 0703722b599..dfcc87cb4bb 100644 --- a/frameworks/Kotlin/vertx-web-kotlin-coroutines/vertx-web-kotlin-coroutines-postgres.dockerfile +++ b/frameworks/Kotlin/vertx-web-kotlin-coroutines/vertx-web-kotlin-coroutines-postgres.dockerfile @@ -1,10 +1,8 @@ -FROM gradle:7.6-jdk17 as gradle +FROM gradle:8.10.2-jdk17 as gradle WORKDIR /vertx-web-kotlin-coroutines -COPY gradle gradle COPY src src COPY build.gradle.kts build.gradle.kts COPY gradle.properties gradle.properties -COPY gradlew gradlew COPY settings.gradle.kts settings.gradle.kts RUN gradle shadowJar diff --git a/frameworks/Kotlin/vertx-web-kotlin-coroutines/vertx-web-kotlin-coroutines.dockerfile b/frameworks/Kotlin/vertx-web-kotlin-coroutines/vertx-web-kotlin-coroutines.dockerfile index 5c9e6378404..dfcc87cb4bb 100644 --- a/frameworks/Kotlin/vertx-web-kotlin-coroutines/vertx-web-kotlin-coroutines.dockerfile +++ b/frameworks/Kotlin/vertx-web-kotlin-coroutines/vertx-web-kotlin-coroutines.dockerfile @@ -1,4 +1,4 @@ -FROM gradle:7.6-jdk17 as gradle +FROM gradle:8.10.2-jdk17 as gradle WORKDIR /vertx-web-kotlin-coroutines COPY src src COPY build.gradle.kts build.gradle.kts diff --git a/frameworks/Kotlin/vertx-web-kotlinx/README.md b/frameworks/Kotlin/vertx-web-kotlinx/README.md index 6c1d6caa252..b9fe8d87eef 100755 --- a/frameworks/Kotlin/vertx-web-kotlinx/README.md +++ b/frameworks/Kotlin/vertx-web-kotlinx/README.md @@ -2,7 +2,7 @@ Vert.x-Web in Kotlin with request handling implemented as much with official kotlinx libraries as possible. -Code is written from scratch to be as concise as possible with common code extracted into common (possibly inline) functions. SQL client implementation details and JVM Options are adapted referring to [the vertx-web portion](../../Java/vertx-web) and [the vertx portion](../../Java/vertx). All requests are handled in coroutines and suspend `await`s are used instead of future compositions. Compared to [the vertx-web-kotlin-coroutines portion](../vertx-web-kotlin-coroutines), besides adopting the Kotlinx libraries, this project simplifies the code by using more built-in Coroutine functions and avoids mutability as much as possible. JSON serialization is implemented with kotlinx.serialization and Fortunes with kotlinx.html. The benchmark is run on the latest LTS version of JVM, 17. +Code is written from scratch to be as concise as possible with common code extracted into common (possibly inline) functions. SQL client implementation details and JVM Options are adapted referring to [the vertx-web portion](../../Java/vertx-web) and [the vertx portion](../../Java/vertx). All requests are handled in coroutines and suspend `await`s are used instead of future compositions. Compared to [the vertx-web-kotlin-coroutines portion](../vertx-web-kotlin-coroutines), besides adopting the Kotlinx libraries, this project simplifies the code by using more built-in Coroutine functions and avoids mutability as much as possible. JSON serialization is implemented with kotlinx.serialization and Fortunes with kotlinx.html. The benchmark is run on the latest LTS version of JVM, 21. ## Test Type Implementation Source Code @@ -27,6 +27,7 @@ The tests were run with: * [Vert.x Reactive PostgreSQL Client](https://vertx.io/docs/vertx-pg-client/java/) * [kotlinx.coroutines](https://github.com/Kotlin/kotlinx.coroutines) * [kotlinx.serialization](https://github.com/Kotlin/kotlinx.serialization) +* [kotlinx-io](https://github.com/Kotlin/kotlinx-io) * [kotlinx.html](https://github.com/Kotlin/kotlinx.html) ## Test URLs diff --git a/frameworks/Kotlin/vertx-web-kotlinx/build.gradle.kts b/frameworks/Kotlin/vertx-web-kotlinx/build.gradle.kts index 232eadaf821..2e0035ab3e7 100644 --- a/frameworks/Kotlin/vertx-web-kotlinx/build.gradle.kts +++ b/frameworks/Kotlin/vertx-web-kotlinx/build.gradle.kts @@ -1,12 +1,9 @@ -import org.jetbrains.kotlin.gradle.dsl.JvmTarget -import org.jetbrains.kotlin.gradle.tasks.KotlinCompile - tasks.wrapper { distributionType = Wrapper.DistributionType.ALL } plugins { - val kotlinVersion = "1.8.10" + val kotlinVersion = "2.0.21" kotlin("jvm") version kotlinVersion kotlin("plugin.serialization") version kotlinVersion application @@ -16,7 +13,8 @@ repositories { mavenCentral() } -val vertxVersion = "4.3.8" +val vertxVersion = "4.5.10" +val kotlinxSerializationVersion = "1.7.3" dependencies { implementation(platform("io.vertx:vertx-stack-depchain:$vertxVersion")) implementation("io.vertx:vertx-web") @@ -24,15 +22,20 @@ dependencies { implementation("io.netty", "netty-transport-native-epoll", classifier = "linux-x86_64") implementation("io.vertx:vertx-lang-kotlin") implementation("io.vertx:vertx-lang-kotlin-coroutines") + runtimeOnly("io.vertx:vertx-io_uring-incubator") + // This dependency has to be added for io_uring to work. + runtimeOnly("io.netty.incubator:netty-incubator-transport-native-io_uring:0.0.25.Final:linux-x86_64") - implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.4") - implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.4.1") - implementation("org.jetbrains.kotlinx:kotlinx-html:0.8.0") - //implementation("org.jetbrains.kotlinx:kotlinx-datetime:0.4.0") -} + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.9.0") -tasks.withType { - compilerOptions.jvmTarget.set(JvmTarget.JVM_17) + implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:$kotlinxSerializationVersion") + implementation("org.jetbrains.kotlinx:kotlinx-serialization-json-io:$kotlinxSerializationVersion") + implementation("org.jetbrains.kotlinx:kotlinx-io-core:0.5.4") + + implementation("org.jetbrains.kotlinx:kotlinx-html:0.11.0") + //implementation("org.jetbrains.kotlinx:kotlinx-datetime:0.4.0") // the latest version is 0.6.1 } +kotlin.jvmToolchain(21) + application.mainClass.set("MainKt") diff --git a/frameworks/Kotlin/vertx-web-kotlinx/gradle/wrapper/gradle-wrapper.jar b/frameworks/Kotlin/vertx-web-kotlinx/gradle/wrapper/gradle-wrapper.jar index ccebba7710deaf9f98673a68957ea02138b60d0a..a4b76b9530d66f5e68d973ea569d8e19de379189 100644 GIT binary patch literal 43583 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 yu?e%!_ptzGB|8GrCfu%p?(_ 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 GZ~q4|mN%#X literal 61608 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 diff --git a/frameworks/Kotlin/vertx-web-kotlinx/gradle/wrapper/gradle-wrapper.properties b/frameworks/Kotlin/vertx-web-kotlinx/gradle/wrapper/gradle-wrapper.properties index 284897427bc..79eb9d003fe 100644 --- a/frameworks/Kotlin/vertx-web-kotlinx/gradle/wrapper/gradle-wrapper.properties +++ b/frameworks/Kotlin/vertx-web-kotlinx/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,7 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.0-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-all.zip networkTimeout=10000 +validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/frameworks/Kotlin/vertx-web-kotlinx/gradlew b/frameworks/Kotlin/vertx-web-kotlinx/gradlew index 79a61d421cc..f5feea6d6b1 100755 --- a/frameworks/Kotlin/vertx-web-kotlinx/gradlew +++ b/frameworks/Kotlin/vertx-web-kotlinx/gradlew @@ -15,6 +15,8 @@ # See the License for the specific language governing permissions and # limitations under the License. # +# SPDX-License-Identifier: Apache-2.0 +# ############################################################################## # @@ -55,7 +57,7 @@ # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template -# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. @@ -83,10 +85,9 @@ done # This is normally unused # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} -APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit - -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' +# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) +APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s +' "$PWD" ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum @@ -133,10 +134,13 @@ location of your Java installation." fi else JAVACMD=java - which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + if ! command -v java >/dev/null 2>&1 + then + die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." + fi fi # Increase the maximum file descriptors if we can. @@ -144,7 +148,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC3045 + # shellcheck disable=SC2039,SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac @@ -152,7 +156,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then '' | soft) :;; #( *) # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC3045 + # shellcheck disable=SC2039,SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac @@ -197,11 +201,15 @@ if "$cygwin" || "$msys" ; then done fi -# Collect all arguments for the java command; -# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of -# shell script including quotes and variable substitutions, so put them in -# double quotes to make sure that they get re-expanded; and -# * put everything else in single quotes, so that it's not re-expanded. + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Collect all arguments for the java command: +# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# and any embedded shellness will be escaped. +# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be +# treated as '${Hostname}' itself on the command line. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ diff --git a/frameworks/Kotlin/vertx-web-kotlinx/gradlew.bat b/frameworks/Kotlin/vertx-web-kotlinx/gradlew.bat index 93e3f59f135..9d21a21834d 100644 --- a/frameworks/Kotlin/vertx-web-kotlinx/gradlew.bat +++ b/frameworks/Kotlin/vertx-web-kotlinx/gradlew.bat @@ -13,6 +13,8 @@ @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem +@rem SPDX-License-Identifier: Apache-2.0 +@rem @if "%DEBUG%"=="" @echo off @rem ########################################################################## @@ -43,11 +45,11 @@ set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 if %ERRORLEVEL% equ 0 goto execute -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. +echo. 1>&2 +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 goto fail @@ -57,11 +59,11 @@ set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto execute -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. +echo. 1>&2 +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 goto fail diff --git a/frameworks/Kotlin/vertx-web-kotlinx/src/main/kotlin/KotlinxIo.kt b/frameworks/Kotlin/vertx-web-kotlinx/src/main/kotlin/KotlinxIo.kt new file mode 100644 index 00000000000..6427b91e85e --- /dev/null +++ b/frameworks/Kotlin/vertx-web-kotlinx/src/main/kotlin/KotlinxIo.kt @@ -0,0 +1,47 @@ +import io.vertx.core.streams.WriteStream +import io.vertx.kotlin.coroutines.coAwait +import kotlinx.coroutines.runBlocking +import kotlinx.io.RawSink +import kotlinx.io.readByteArray +import io.vertx.core.buffer.Buffer as VertxBuffer +import kotlinx.io.Buffer as KotlinxIoBuffer + +@Suppress("NOTHING_TO_INLINE") +private inline fun Long.toIntOrThrow(): Int { + require(this in Int.MIN_VALUE.toLong()..Int.MAX_VALUE.toLong()) + return toInt() +} + +@JvmInline +value class VertxBufferWriteStreamRawSink(val writeStream: WriteStream) : RawSink { + override fun write(source: KotlinxIoBuffer, byteCount: Long) { + runBlocking { + writeStream.write(VertxBuffer.buffer(source.readByteArray(byteCount.toIntOrThrow()))).coAwait() + } + } + + override fun flush() {} + + override fun close() { + writeStream.end() + } +} + +// not used currently +fun WriteStream.toRawSink(): RawSink = + VertxBufferWriteStreamRawSink(this) + + +@JvmInline +value class VertxBufferRawSink(val vertxBuffer: VertxBuffer) : RawSink { + override fun write(source: KotlinxIoBuffer, byteCount: Long) { + vertxBuffer.appendBytes(source.readByteArray(byteCount.toIntOrThrow())) + } + + override fun flush() {} + + override fun close() {} +} + +fun VertxBuffer.toRawSink(): RawSink = + VertxBufferRawSink(this) diff --git a/frameworks/Kotlin/vertx-web-kotlinx/src/main/kotlin/Main.kt b/frameworks/Kotlin/vertx-web-kotlinx/src/main/kotlin/Main.kt index 75cbd79e3cd..987c22162b3 100644 --- a/frameworks/Kotlin/vertx-web-kotlinx/src/main/kotlin/Main.kt +++ b/frameworks/Kotlin/vertx-web-kotlinx/src/main/kotlin/Main.kt @@ -2,10 +2,10 @@ import io.vertx.core.Vertx import io.vertx.core.impl.cpu.CpuCoreSensor import io.vertx.kotlin.core.deploymentOptionsOf import io.vertx.kotlin.core.vertxOptionsOf -import io.vertx.kotlin.coroutines.await +import io.vertx.kotlin.coroutines.coAwait import java.util.logging.Logger -const val SERVER_NAME = "Vert.x-Web Kotlinx Benchmark" +const val SERVER_NAME = "Vert.x-Web Kotlinx Benchmark server" val logger = Logger.getLogger("Vert.x-Web Kotlinx Benchmark") suspend fun main(args: Array) { @@ -19,6 +19,6 @@ suspend fun main(args: Array) { it.printStackTrace() } vertx.deployVerticle({ MainVerticle(hasDb) }, deploymentOptionsOf(instances = CpuCoreSensor.availableProcessors())) - .await() + .coAwait() logger.info("$SERVER_NAME started.") } diff --git a/frameworks/Kotlin/vertx-web-kotlinx/src/main/kotlin/MainVerticle.kt b/frameworks/Kotlin/vertx-web-kotlinx/src/main/kotlin/MainVerticle.kt index 9d16710709e..2bd701fa083 100644 --- a/frameworks/Kotlin/vertx-web-kotlinx/src/main/kotlin/MainVerticle.kt +++ b/frameworks/Kotlin/vertx-web-kotlinx/src/main/kotlin/MainVerticle.kt @@ -1,4 +1,5 @@ import io.netty.channel.unix.Errors.NativeIoException +import io.vertx.core.buffer.Buffer import io.vertx.core.http.HttpHeaders import io.vertx.core.http.HttpServer import io.vertx.core.http.HttpServerRequest @@ -7,39 +8,28 @@ import io.vertx.ext.web.Route import io.vertx.ext.web.Router import io.vertx.ext.web.RoutingContext import io.vertx.kotlin.core.http.httpServerOptionsOf +import io.vertx.kotlin.coroutines.CoroutineRouterSupport import io.vertx.kotlin.coroutines.CoroutineVerticle -import io.vertx.kotlin.coroutines.await +import io.vertx.kotlin.coroutines.coAwait import io.vertx.kotlin.pgclient.pgConnectOptionsOf import io.vertx.pgclient.PgConnection import io.vertx.sqlclient.PreparedQuery import io.vertx.sqlclient.Row import io.vertx.sqlclient.RowSet import io.vertx.sqlclient.Tuple -import kotlinx.coroutines.* +import kotlinx.coroutines.Dispatchers import kotlinx.html.* import kotlinx.html.stream.appendHTML +import kotlinx.io.buffered +import kotlinx.serialization.ExperimentalSerializationApi import kotlinx.serialization.Serializable -import kotlinx.serialization.encodeToString +import kotlinx.serialization.SerializationStrategy import kotlinx.serialization.json.Json -import java.net.SocketException +import kotlinx.serialization.json.io.encodeToSink import java.time.ZonedDateTime import java.time.format.DateTimeFormatter -class MainVerticle(val hasDb: Boolean) : CoroutineVerticle() { - inline fun Route.checkedCoroutineHandlerUnconfined(crossinline requestHandler: suspend (RoutingContext) -> Unit): Route = - handler { ctx -> - /* Some conclusions from the Plaintext test results with trailing `await()`s: - 1. `launch { /*...*/ }` < `launch(start = CoroutineStart.UNDISPATCHED) { /*...*/ }` < `launch(Dispatchers.Unconfined) { /*...*/ }`. - 1. `launch { /*...*/ }` without `context` or `start` lead to `io.netty.channel.StacklessClosedChannelException` and `io.netty.channel.unix.Errors$NativeIoException: sendAddress(..) failed: Connection reset by peer`. */ - launch(Dispatchers.Unconfined) { - try { - requestHandler(ctx) - } catch (t: Throwable) { - ctx.fail(t) - } - } - } - +class MainVerticle(val hasDb: Boolean) : CoroutineVerticle(), CoroutineRouterSupport { // `PgConnection`s as used in the "vertx" portion offers better performance than `PgPool`s. lateinit var pgConnection: PgConnection lateinit var date: String @@ -68,7 +58,7 @@ class MainVerticle(val hasDb: Boolean) : CoroutineVerticle() { cachePreparedStatements = true, pipeliningLimit = 100000 ) - ).await() + ).coAwait() selectWorldQuery = pgConnection.preparedQuery(SELECT_WORLD_SQL) selectFortuneQuery = pgConnection.preparedQuery(SELECT_FORTUNE_SQL) @@ -81,15 +71,19 @@ class MainVerticle(val hasDb: Boolean) : CoroutineVerticle() { .requestHandler(Router.router(vertx).apply { routes() }) .exceptionHandler { // wrk resets the connections when benchmarking is finished. - if ((it is NativeIoException && it.message == "recvAddress(..) failed: Connection reset by peer") - || (it is SocketException && it.message == "Connection reset") + if ( + // for epoll + /*(it is NativeIoException && it.message == "recvAddress(..) failed: Connection reset by peer") + || (it is SocketException && it.message == "Connection reset")*/ + // for io_uring + it is NativeIoException && it.message == "io_uring read(..) failed: Connection reset by peer" ) return@exceptionHandler logger.info("Exception in HttpServer: $it") it.printStackTrace() } - .listen().await() + .listen().coAwait() } @@ -110,14 +104,46 @@ class MainVerticle(val hasDb: Boolean) : CoroutineVerticle() { putHeader(HttpHeaders.CONTENT_TYPE, "application/json") } - inline fun Route.jsonResponseHandler(crossinline requestHandler: suspend (RoutingContext) -> @Serializable T) = - checkedCoroutineHandlerUnconfined { + + fun Route.coHandlerUnconfined(requestHandler: suspend (RoutingContext) -> Unit): Route = + /* Some conclusions from the Plaintext test results with trailing `await()`s: + 1. `launch { /*...*/ }` < `launch(start = CoroutineStart.UNDISPATCHED) { /*...*/ }` < `launch(Dispatchers.Unconfined) { /*...*/ }`. + 1. `launch { /*...*/ }` without `context` or `start` lead to `io.netty.channel.StacklessClosedChannelException` and `io.netty.channel.unix.Errors$NativeIoException: sendAddress(..) failed: Connection reset by peer`. */ + coHandler(Dispatchers.Unconfined, requestHandler) + + inline fun Route.jsonResponseCoHandler( + serializer: SerializationStrategy, + crossinline requestHandler: suspend (RoutingContext) -> @Serializable T + ) = + coHandlerUnconfined { it.response().run { putJsonResponseHeader() - end(Json.encodeToString(requestHandler(it)))/*.await()*/ + + /* + // approach 1 + end(Json.encodeToString(serializer, requestHandler(it)))/*.coAwait()*/ + */ + + /* + // approach 2 + // java.lang.IllegalStateException: You must set the Content-Length header to be the total size of the message body BEFORE sending any data if you are not using HTTP chunked encoding. + toRawSink().buffered().use { bufferedSink -> + @OptIn(ExperimentalSerializationApi::class) + Json.encodeToSink(serializer, requestHandler(it), bufferedSink) + } + */ + + // approach 3 + end(Buffer.buffer().apply { + toRawSink().buffered().use { bufferedSink -> + @OptIn(ExperimentalSerializationApi::class) + Json.encodeToSink(serializer, requestHandler(it), bufferedSink) + } + }) } } + suspend fun selectRandomWorlds(queries: Int): List { val rowSets = List(queries) { selectWorldQuery.execute(Tuple.of(randomIntBetween1And10000())) @@ -126,23 +152,23 @@ class MainVerticle(val hasDb: Boolean) : CoroutineVerticle() { } fun Router.routes() { - get("/json").jsonResponseHandler { + get("/json").jsonResponseCoHandler(Serializers.message) { jsonSerializationMessage } - get("/db").jsonResponseHandler { - val rowSet = selectWorldQuery.execute(Tuple.of(randomIntBetween1And10000())).await() + get("/db").jsonResponseCoHandler(Serializers.world) { + val rowSet = selectWorldQuery.execute(Tuple.of(randomIntBetween1And10000())).coAwait() rowSet.single().toWorld() } - get("/queries").jsonResponseHandler { + get("/queries").jsonResponseCoHandler(Serializers.worlds) { val queries = it.request().getQueries() selectRandomWorlds(queries) } - get("/fortunes").checkedCoroutineHandlerUnconfined { + get("/fortunes").coHandlerUnconfined { val fortunes = mutableListOf() - selectFortuneQuery.execute().await() + selectFortuneQuery.execute().coAwait() .mapTo(fortunes) { it.toFortune() } fortunes.add(Fortune(0, "Additional fortune added at request time.")) @@ -173,11 +199,11 @@ class MainVerticle(val hasDb: Boolean) : CoroutineVerticle() { it.response().run { putCommonHeaders() putHeader(HttpHeaders.CONTENT_TYPE, "text/html; charset=utf-8") - end(htmlString)/*.await()*/ + end(htmlString)/*.coAwait()*/ } } - get("/updates").jsonResponseHandler { + get("/updates").jsonResponseCoHandler(Serializers.worlds) { val queries = it.request().getQueries() val worlds = selectRandomWorlds(queries) val updatedWorlds = worlds.map { it.copy(randomNumber = randomIntBetween1And10000()) } @@ -185,7 +211,7 @@ class MainVerticle(val hasDb: Boolean) : CoroutineVerticle() { // Approach 1 // The updated worlds need to be sorted first to avoid deadlocks. updateWordQuery - .executeBatch(updatedWorlds.sortedBy { it.id }.map { Tuple.of(it.randomNumber, it.id) }).await() + .executeBatch(updatedWorlds.sortedBy { it.id }.map { Tuple.of(it.randomNumber, it.id) }).coAwait() /* // Approach 2, worse performance @@ -197,11 +223,11 @@ class MainVerticle(val hasDb: Boolean) : CoroutineVerticle() { updatedWorlds } - get("/plaintext").checkedCoroutineHandlerUnconfined { + get("/plaintext").coHandlerUnconfined { it.response().run { putCommonHeaders() putHeader(HttpHeaders.CONTENT_TYPE, "text/plain") - end("Hello, World!")/*.await()*/ + end("Hello, World!")/*.coAwait()*/ } } } diff --git a/frameworks/Kotlin/vertx-web-kotlinx/src/main/kotlin/Serializers.kt b/frameworks/Kotlin/vertx-web-kotlinx/src/main/kotlin/Serializers.kt new file mode 100644 index 00000000000..c975fc07fdd --- /dev/null +++ b/frameworks/Kotlin/vertx-web-kotlinx/src/main/kotlin/Serializers.kt @@ -0,0 +1,7 @@ +import kotlinx.serialization.serializer + +object Serializers { + val message = serializer() + val world = serializer() + val worlds = serializer>() +} \ No newline at end of file diff --git a/frameworks/Kotlin/vertx-web-kotlinx/src/main/kotlin/VertxCoroutine.kt b/frameworks/Kotlin/vertx-web-kotlinx/src/main/kotlin/VertxCoroutine.kt index bb8d419d399..d6230fef7f7 100644 --- a/frameworks/Kotlin/vertx-web-kotlinx/src/main/kotlin/VertxCoroutine.kt +++ b/frameworks/Kotlin/vertx-web-kotlinx/src/main/kotlin/VertxCoroutine.kt @@ -1,6 +1,5 @@ -import io.vertx.core.CompositeFuture import io.vertx.core.Future -import io.vertx.kotlin.coroutines.await +import io.vertx.kotlin.coroutines.coAwait suspend fun List>.awaitAll(): List = - CompositeFuture.all(this).await().list() + Future.all(this).coAwait().list() diff --git a/frameworks/Kotlin/vertx-web-kotlinx/vertx-web-kotlinx-postgresql.dockerfile b/frameworks/Kotlin/vertx-web-kotlinx/vertx-web-kotlinx-postgresql.dockerfile index 55c7c2c6803..17b43ebcb5c 100644 --- a/frameworks/Kotlin/vertx-web-kotlinx/vertx-web-kotlinx-postgresql.dockerfile +++ b/frameworks/Kotlin/vertx-web-kotlinx/vertx-web-kotlinx-postgresql.dockerfile @@ -1,12 +1,11 @@ -FROM gradle:8.0-jdk17 +FROM gradle:8.10.2-jdk21 WORKDIR /vertx-web-kotlinx COPY build.gradle.kts build.gradle.kts COPY settings.gradle.kts settings.gradle.kts COPY gradle.properties gradle.properties COPY src src -RUN gradle assembleDist -RUN tar -xf build/distributions/vertx-web-kotlinx-benchmark.tar +RUN gradle --no-daemon installDist EXPOSE 8080 @@ -25,4 +24,4 @@ CMD export JAVA_OPTS=" \ -Dio.netty.buffer.checkBounds=false \ -Dio.netty.buffer.checkAccessible=false \ " && \ - vertx-web-kotlinx-benchmark/bin/vertx-web-kotlinx-benchmark true + build/install/vertx-web-kotlinx-benchmark/bin/vertx-web-kotlinx-benchmark true diff --git a/frameworks/Kotlin/vertx-web-kotlinx/vertx-web-kotlinx.dockerfile b/frameworks/Kotlin/vertx-web-kotlinx/vertx-web-kotlinx.dockerfile index 63d2d4a68ad..4bdc993707d 100644 --- a/frameworks/Kotlin/vertx-web-kotlinx/vertx-web-kotlinx.dockerfile +++ b/frameworks/Kotlin/vertx-web-kotlinx/vertx-web-kotlinx.dockerfile @@ -1,12 +1,11 @@ -FROM gradle:8.0-jdk17 +FROM gradle:8.10.2-jdk21 WORKDIR /vertx-web-kotlinx COPY build.gradle.kts build.gradle.kts COPY settings.gradle.kts settings.gradle.kts COPY gradle.properties gradle.properties COPY src src -RUN gradle assembleDist -RUN tar -xf build/distributions/vertx-web-kotlinx-benchmark.tar +RUN gradle --no-daemon installDist EXPOSE 8080 @@ -25,4 +24,4 @@ CMD export JAVA_OPTS=" \ -Dio.netty.buffer.checkBounds=false \ -Dio.netty.buffer.checkAccessible=false \ " && \ - vertx-web-kotlinx-benchmark/bin/vertx-web-kotlinx-benchmark false + build/install/vertx-web-kotlinx-benchmark/bin/vertx-web-kotlinx-benchmark false From 59df50871130a25ad4b176dceca7e60b99591fba Mon Sep 17 00:00:00 2001 From: Petrik de Heus Date: Mon, 4 Nov 2024 19:42:27 +0100 Subject: [PATCH 198/204] [ruby/rack] Use java_tune.sh script for rack-jruby (#9372) This should improve `rack-jruby` performance. Also remove `java_tune.sh` from frameworks that no longer test with JRuby. --- .../{rack-sequel => rack}/config/java_tune.sh | 0 frameworks/Ruby/rack/rack-jruby.dockerfile | 2 ++ .../Ruby/sinatra-sequel/config/java_tune.sh | 18 ------------------ 3 files changed, 2 insertions(+), 18 deletions(-) rename frameworks/Ruby/{rack-sequel => rack}/config/java_tune.sh (100%) delete mode 100644 frameworks/Ruby/sinatra-sequel/config/java_tune.sh diff --git a/frameworks/Ruby/rack-sequel/config/java_tune.sh b/frameworks/Ruby/rack/config/java_tune.sh similarity index 100% rename from frameworks/Ruby/rack-sequel/config/java_tune.sh rename to frameworks/Ruby/rack/config/java_tune.sh diff --git a/frameworks/Ruby/rack/rack-jruby.dockerfile b/frameworks/Ruby/rack/rack-jruby.dockerfile index ab06ae132ed..c280cca6ac8 100644 --- a/frameworks/Ruby/rack/rack-jruby.dockerfile +++ b/frameworks/Ruby/rack/rack-jruby.dockerfile @@ -13,4 +13,6 @@ COPY . . EXPOSE 8080 +CMD config/java_tune.sh + CMD bundle exec puma -C config/puma.rb -b tcp://0.0.0.0:8080 -e production diff --git a/frameworks/Ruby/sinatra-sequel/config/java_tune.sh b/frameworks/Ruby/sinatra-sequel/config/java_tune.sh deleted file mode 100644 index 412b1e74fdc..00000000000 --- a/frameworks/Ruby/sinatra-sequel/config/java_tune.sh +++ /dev/null @@ -1,18 +0,0 @@ -#!/bin/sh -stack_size=1 -cache_size=240 -meta_size=192 -avail_mem=$(awk '/^MemAvailable/ { print int(0.6 * $2 / 1024); exit }' /proc/meminfo) -heap_size=$(( avail_mem - meta_size - cache_size - (stack_size * MAX_CONCURRENCY * THREAD_FACTOR) )) - -JRUBY_OPTS="-J-server -J-XX:+AggressiveOpts -J-Djava.net.preferIPv4Stack=true" -#JRUBY_OPTS="$JRUBY_OPTS -J-XX:+UseSerialGC" -JRUBY_OPTS="$JRUBY_OPTS -J-XX:+CMSClassUnloadingEnabled -J-XX:+UseConcMarkSweepGC" -#JRUBY_OPTS="$JRUBY_OPTS -J-XX:+UseG1GC -J-XX:+UseStringDeduplication" -JRUBY_OPTS="$JRUBY_OPTS -J-Xms${heap_size}m -J-Xmx${heap_size}m" -JRUBY_OPTS="$JRUBY_OPTS -J-Xss${stack_size}m" -JRUBY_OPTS="$JRUBY_OPTS -J-XX:MaxMetaspaceSize=${meta_size}m" -JRUBY_OPTS="$JRUBY_OPTS -J-XX:ReservedCodeCacheSize=${cache_size}m" -JRUBY_OPTS="$JRUBY_OPTS -Xcompile.invokedynamic=true -J-XX:+UseNUMA -J-XX:+AlwaysPreTouch" - -export JRUBY_OPTS From fb4a84fbcd7ed849e8f7d1eb0b315fb33578d436 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=A5=BF=E4=B8=9C?= Date: Tue, 5 Nov 2024 02:42:55 +0800 Subject: [PATCH 199/204] [java] Add solon-vertx (#9371) * Update Solon Version To 2.9.1 * Update Solon Version To 2.9.1 * Update Solon Jdk To 21 * Update Solon Jdk To 21 * Update Solon Jdk To 21 * Update Solon Jdk To 21 * Update Solon Jdk To 21 * Update Solon Version To 2.9.2 * Add Solon-Virtual * Remove solon-virtual * Update Solon Version To 3.0.2 * Add Solon-Vertx * Tweak description * Tweak the dockerfile * Tweak the dockerfile * Tweak config * Tweak dockefile name * Add FilterImpl * Add FilterImpl * The json plugin is changed to jackson * Update Solon Jdk To 23 * Update Solon-Vertx Jdk To 23 * Solon-vertx is restored to jdk 21 * Solon is restored to jdk 21 * Solon-vertx adjusts the Date output format * Solon is restored to jdk 21 --- frameworks/Java/solon-vertx/README.md | 23 +++++++ .../Java/solon-vertx/benchmark_config.json | 26 ++++++++ frameworks/Java/solon-vertx/config.toml | 15 +++++ frameworks/Java/solon-vertx/pom.xml | 61 +++++++++++++++++++ .../Java/solon-vertx/solon-vertx.dockerfile | 13 ++++ .../solon-vertx/src/main/java/hello/Main.java | 13 ++++ .../java/hello/controller/FilterImpl.java | 23 +++++++ .../hello/controller/HelloController.java | 25 ++++++++ .../src/main/java/hello/model/Message.java | 21 +++++++ .../src/main/resources/app.properties | 1 + frameworks/Java/solon/pom.xml | 2 +- 11 files changed, 222 insertions(+), 1 deletion(-) create mode 100644 frameworks/Java/solon-vertx/README.md create mode 100644 frameworks/Java/solon-vertx/benchmark_config.json create mode 100644 frameworks/Java/solon-vertx/config.toml create mode 100644 frameworks/Java/solon-vertx/pom.xml create mode 100644 frameworks/Java/solon-vertx/solon-vertx.dockerfile create mode 100644 frameworks/Java/solon-vertx/src/main/java/hello/Main.java create mode 100644 frameworks/Java/solon-vertx/src/main/java/hello/controller/FilterImpl.java create mode 100644 frameworks/Java/solon-vertx/src/main/java/hello/controller/HelloController.java create mode 100644 frameworks/Java/solon-vertx/src/main/java/hello/model/Message.java create mode 100644 frameworks/Java/solon-vertx/src/main/resources/app.properties diff --git a/frameworks/Java/solon-vertx/README.md b/frameworks/Java/solon-vertx/README.md new file mode 100644 index 00000000000..40b8ab3b2cf --- /dev/null +++ b/frameworks/Java/solon-vertx/README.md @@ -0,0 +1,23 @@ +# solon-vertx Benchmarking Test + + +This is the solon-vertx portion of a [benchmarking test suite](../) comparing a variety of web development platforms. + +### JSON Encoding Test +* [JSON test source](src/main/java/hello/Main.java) +* [Plaintext test source](src/main/java/hello/Main.java) + +## Versions + +* [Java OpenJDK 21](http://openjdk.java.net/) +* [solon 3.0.2](https://github.com/noear/solon) + +## Test URLs + +### JSON Encoding Test + + http://localhost:8080/json + +### Plaintext Encoding Test + + http://localhost:8080/plaintext \ No newline at end of file diff --git a/frameworks/Java/solon-vertx/benchmark_config.json b/frameworks/Java/solon-vertx/benchmark_config.json new file mode 100644 index 00000000000..3b7de26f5d4 --- /dev/null +++ b/frameworks/Java/solon-vertx/benchmark_config.json @@ -0,0 +1,26 @@ +{ + "framework": "solon-vertx", + "tests": [ + { + "default": { + "json_url": "/json", + "plaintext_url": "/plaintext", + "port": 8080, + "approach": "Realistic", + "classification": "Fullstack", + "database": "None", + "framework": "solon", + "language": "Java", + "flavor": "None", + "orm": "Micro", + "platform": "Netty", + "webserver": "None", + "os": "Linux", + "database_os": "Linux", + "display_name": "solon-vertx", + "notes": "", + "versus": "solon" + } + } + ] +} diff --git a/frameworks/Java/solon-vertx/config.toml b/frameworks/Java/solon-vertx/config.toml new file mode 100644 index 00000000000..8306ab94cd1 --- /dev/null +++ b/frameworks/Java/solon-vertx/config.toml @@ -0,0 +1,15 @@ +[framework] +name = "solon-vertx" + +[main] +urls.plaintext = "/plaintext" +urls.json = "/json" +approach = "Realistic" +classification = "Platform" +database = "None" +database_os = "Linux" +os = "Linux" +orm = "Micro" +platform = "Netty" +webserver = "None" +versus = "solon" diff --git a/frameworks/Java/solon-vertx/pom.xml b/frameworks/Java/solon-vertx/pom.xml new file mode 100644 index 00000000000..2546baecf35 --- /dev/null +++ b/frameworks/Java/solon-vertx/pom.xml @@ -0,0 +1,61 @@ + + 4.0.0 + + + org.noear + solon-parent + 3.0.2 + + + hello + hello-solon + 1.0 + jar + + + 21 + + + + + org.noear + solon-boot-vertx + + + + org.noear + solon-serialization-jackson + + + + + ${project.artifactId} + + + + org.apache.maven.plugins + maven-assembly-plugin + + + jar-with-dependencies + + + + hello.Main + + + + + + make-assembly + package + + single + + + + + + + diff --git a/frameworks/Java/solon-vertx/solon-vertx.dockerfile b/frameworks/Java/solon-vertx/solon-vertx.dockerfile new file mode 100644 index 00000000000..c387938661c --- /dev/null +++ b/frameworks/Java/solon-vertx/solon-vertx.dockerfile @@ -0,0 +1,13 @@ +FROM maven:3.9.7-amazoncorretto-21 as maven +WORKDIR /solon +COPY pom.xml pom.xml +COPY src src +RUN mvn compile assembly:single -q + +FROM openjdk:21-jdk-slim +WORKDIR /solon +COPY --from=maven /solon/target/hello-solon.jar app.jar + +EXPOSE 8080 + +CMD ["java", "-server", "-cp", "app.jar", "hello.Main"] \ No newline at end of file diff --git a/frameworks/Java/solon-vertx/src/main/java/hello/Main.java b/frameworks/Java/solon-vertx/src/main/java/hello/Main.java new file mode 100644 index 00000000000..bc6467e87af --- /dev/null +++ b/frameworks/Java/solon-vertx/src/main/java/hello/Main.java @@ -0,0 +1,13 @@ +package hello; + +import org.noear.solon.Solon; + +/** + * @author noear + * @version V1.0 + */ +public class Main { + public static void main(String[] args) { + Solon.start(Main.class, args); + } +} diff --git a/frameworks/Java/solon-vertx/src/main/java/hello/controller/FilterImpl.java b/frameworks/Java/solon-vertx/src/main/java/hello/controller/FilterImpl.java new file mode 100644 index 00000000000..7fb22e497f8 --- /dev/null +++ b/frameworks/Java/solon-vertx/src/main/java/hello/controller/FilterImpl.java @@ -0,0 +1,23 @@ +package hello.controller; + +import org.noear.solon.annotation.Component; +import org.noear.solon.core.handle.Context; +import org.noear.solon.core.handle.Filter; +import org.noear.solon.core.handle.FilterChain; + +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.Date; + +@Component +public class FilterImpl implements Filter { + private static DateFormat DATE_FORMAT = new SimpleDateFormat("EEE, d MMM yyyyy HH:mm:ss z"); + + @Override + public void doFilter(Context ctx, FilterChain chain) throws Throwable { + String dateString = DATE_FORMAT.format(new Date()); + ctx.headerSet("Date", dateString); + ctx.headerSet("Server", "solon-boot-vertx"); + chain.doFilter(ctx); + } +} diff --git a/frameworks/Java/solon-vertx/src/main/java/hello/controller/HelloController.java b/frameworks/Java/solon-vertx/src/main/java/hello/controller/HelloController.java new file mode 100644 index 00000000000..77049043e97 --- /dev/null +++ b/frameworks/Java/solon-vertx/src/main/java/hello/controller/HelloController.java @@ -0,0 +1,25 @@ +package hello.controller; + +import org.noear.solon.annotation.Controller; +import org.noear.solon.annotation.Get; +import org.noear.solon.annotation.Mapping; +import hello.model.Message; + +/** + * @author noear + * @version V1.0 + */ +@Controller +public class HelloController { + @Get + @Mapping("plaintext") + public String plaintext() { + return "Hello, World!"; + } + + @Get + @Mapping("json") + public Message json() { + return new Message("Hello, World!"); + } +} diff --git a/frameworks/Java/solon-vertx/src/main/java/hello/model/Message.java b/frameworks/Java/solon-vertx/src/main/java/hello/model/Message.java new file mode 100644 index 00000000000..235dd2d86dd --- /dev/null +++ b/frameworks/Java/solon-vertx/src/main/java/hello/model/Message.java @@ -0,0 +1,21 @@ +package hello.model; + +/** + * @author noear + * @version V1.0 + */ +public class Message { + private String message; + + public Message(String message) { + this.message = message; + } + + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } +} diff --git a/frameworks/Java/solon-vertx/src/main/resources/app.properties b/frameworks/Java/solon-vertx/src/main/resources/app.properties new file mode 100644 index 00000000000..26a5df70351 --- /dev/null +++ b/frameworks/Java/solon-vertx/src/main/resources/app.properties @@ -0,0 +1 @@ +server.http.ioBound=false \ No newline at end of file diff --git a/frameworks/Java/solon/pom.xml b/frameworks/Java/solon/pom.xml index 0c9d8d570ce..428d95b35b7 100644 --- a/frameworks/Java/solon/pom.xml +++ b/frameworks/Java/solon/pom.xml @@ -25,7 +25,7 @@ org.noear - solon-serialization-snack3 + solon-serialization-jackson From 180eba8f3a766202bc5c7d0a2e59a78db5a4971c Mon Sep 17 00:00:00 2001 From: Petrik de Heus Date: Mon, 4 Nov 2024 19:46:04 +0100 Subject: [PATCH 200/204] [crystal/kemal] Update crystal and Kemal (#9368) --- frameworks/Crystal/kemal/kemal.dockerfile | 2 +- frameworks/Crystal/kemal/shard.lock | 2 +- frameworks/Crystal/kemal/shard.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/frameworks/Crystal/kemal/kemal.dockerfile b/frameworks/Crystal/kemal/kemal.dockerfile index baafb59538e..d5890857891 100644 --- a/frameworks/Crystal/kemal/kemal.dockerfile +++ b/frameworks/Crystal/kemal/kemal.dockerfile @@ -1,4 +1,4 @@ -FROM crystallang/crystal:1.12.1 +FROM crystallang/crystal:1.14.0 WORKDIR /kemal COPY views views diff --git a/frameworks/Crystal/kemal/shard.lock b/frameworks/Crystal/kemal/shard.lock index c7bf83e3078..9340b31d88b 100644 --- a/frameworks/Crystal/kemal/shard.lock +++ b/frameworks/Crystal/kemal/shard.lock @@ -18,7 +18,7 @@ shards: kemal: git: https://github.com/kemalcr/kemal.git - version: 1.5.0 + version: 1.6.0 pg: git: https://github.com/will/crystal-pg.git diff --git a/frameworks/Crystal/kemal/shard.yml b/frameworks/Crystal/kemal/shard.yml index 2277be2b8b7..6ab59c26264 100644 --- a/frameworks/Crystal/kemal/shard.yml +++ b/frameworks/Crystal/kemal/shard.yml @@ -9,7 +9,7 @@ dependencies: version: 0.28.0 kemal: github: kemalcr/kemal - version: 1.5.0 + version: 1.6.0 redis: github: stefanwille/crystal-redis version: 2.8.0 From 09bd0281be2c77dcc0a1a1e06f300803c182e6ad Mon Sep 17 00:00:00 2001 From: Petrik de Heus Date: Mon, 4 Nov 2024 19:46:25 +0100 Subject: [PATCH 201/204] [ruby] Update Passenger 6.0.23 and run on ruby:3.4-rc (#9366) --- frameworks/Ruby/rack-sequel/Gemfile | 17 +++++++++-------- frameworks/Ruby/rack-sequel/README.md | 2 +- .../rack-sequel-passenger-mri.dockerfile | 2 +- ...ack-sequel-postgres-passenger-mri.dockerfile | 2 +- frameworks/Ruby/roda-sequel/Gemfile | 1 + frameworks/Ruby/roda-sequel/README.md | 2 +- ...oda-sequel-postgres-passenger-mri.dockerfile | 2 +- ...tra-sequel-postgres-passenger-mri.dockerfile | 2 +- .../sinatra-postgres-passenger-mri.dockerfile | 2 +- 9 files changed, 17 insertions(+), 15 deletions(-) diff --git a/frameworks/Ruby/rack-sequel/Gemfile b/frameworks/Ruby/rack-sequel/Gemfile index 22e0dd418b8..12b60ef57cf 100644 --- a/frameworks/Ruby/rack-sequel/Gemfile +++ b/frameworks/Ruby/rack-sequel/Gemfile @@ -1,20 +1,21 @@ source 'https://rubygems.org' +gem 'base64' # required by passenger on Ruby 3.4 gem 'json', '~> 2.0' gem 'oj', '~> 3.14', platforms: %i[ruby mswin] -gem 'passenger', '~> 6.0', :platforms=>[:ruby, :mswin], :require=>false -gem 'puma', '~> 6.4', :require=>false +gem 'passenger', '~> 6.0', platforms: [:ruby, :mswin], require: false +gem 'puma', '~> 6.4', require: false gem 'sequel', '~> 5.0' gem 'rack', '~> 3.0' -gem 'unicorn', '~> 6.1', :platforms=>[:ruby, :mswin], :require=>false +gem 'unicorn', '~> 6.1', platforms: [:ruby, :mswin], require: false group :mysql do - gem 'jdbc-mysql', '~> 5.1', :platforms=>:jruby, :require=>'jdbc/mysql' - gem 'mysql2', '~> 0.5', :platforms=>[:ruby, :mswin] + gem 'jdbc-mysql', '~> 5.1', platforms: :jruby, require: 'jdbc/mysql' + gem 'mysql2', '~> 0.4', platforms: [:ruby, :mswin] end group :postgresql do - gem 'jdbc-postgres', '~> 9.4', :platforms=>:jruby, :require=>'jdbc/postgres' - gem 'pg', '~> 1.5', :platforms=>[:ruby, :mswin] - gem 'sequel_pg', '~> 1.6', :platforms=>:ruby, :require=>false + gem 'jdbc-postgres', '~> 9.4', platforms: :jruby, require: 'jdbc/postgres' + gem 'pg', '~> 1.5', platforms: [:ruby, :mswin] + gem 'sequel_pg', '~> 1.6', platforms: :ruby, require: false end diff --git a/frameworks/Ruby/rack-sequel/README.md b/frameworks/Ruby/rack-sequel/README.md index 11563d8ffeb..b3a02d90b91 100644 --- a/frameworks/Ruby/rack-sequel/README.md +++ b/frameworks/Ruby/rack-sequel/README.md @@ -14,7 +14,7 @@ The tests will be run with: * [Ruby 3.3](http://www.ruby-lang.org) * [Puma 6](http://puma.io) -* [Passenger 5](https://www.phusionpassenger.com) +* [Passenger 6](https://www.phusionpassenger.com) * [Unicorn 5](https://bogomips.org/unicorn/) * [Rack 2](http://rack.rubyforge.org) * [Sequel 5](http://sequel.jeremyevans.net) diff --git a/frameworks/Ruby/rack-sequel/rack-sequel-passenger-mri.dockerfile b/frameworks/Ruby/rack-sequel/rack-sequel-passenger-mri.dockerfile index 9482a004540..c0de276d2ce 100644 --- a/frameworks/Ruby/rack-sequel/rack-sequel-passenger-mri.dockerfile +++ b/frameworks/Ruby/rack-sequel/rack-sequel-passenger-mri.dockerfile @@ -1,4 +1,4 @@ -FROM ruby:3.3 +FROM ruby:3.4-rc ADD ./ /rack-sequel diff --git a/frameworks/Ruby/rack-sequel/rack-sequel-postgres-passenger-mri.dockerfile b/frameworks/Ruby/rack-sequel/rack-sequel-postgres-passenger-mri.dockerfile index 2765c0c4f89..0346a44eb1b 100644 --- a/frameworks/Ruby/rack-sequel/rack-sequel-postgres-passenger-mri.dockerfile +++ b/frameworks/Ruby/rack-sequel/rack-sequel-postgres-passenger-mri.dockerfile @@ -1,4 +1,4 @@ -FROM ruby:3.3 +FROM ruby:3.4-rc ADD ./ /rack-sequel diff --git a/frameworks/Ruby/roda-sequel/Gemfile b/frameworks/Ruby/roda-sequel/Gemfile index e511bb3d848..c5dd09c3375 100644 --- a/frameworks/Ruby/roda-sequel/Gemfile +++ b/frameworks/Ruby/roda-sequel/Gemfile @@ -1,5 +1,6 @@ source "https://rubygems.org" +gem 'base64' # required by passenger on Ruby 3.4 gem "erubi", "~> 1.12" gem "passenger", "~> 6.0", platforms: %i[ruby mswin], require: false gem "puma", "~> 6.2", require: false diff --git a/frameworks/Ruby/roda-sequel/README.md b/frameworks/Ruby/roda-sequel/README.md index 1ca9c7b55a9..a409974a10f 100644 --- a/frameworks/Ruby/roda-sequel/README.md +++ b/frameworks/Ruby/roda-sequel/README.md @@ -14,7 +14,7 @@ The tests will be run with: * [Ruby 3.3](http://www.ruby-lang.org) * [Puma 6](http://puma.io) -* [Passenger 5](https://www.phusionpassenger.com) +* [Passenger 6](https://www.phusionpassenger.com) * [Unicorn 5](https://bogomips.org/unicorn/) * [Roda 3](http://roda.jeremyevans.net) * [Sequel 5](http://sequel.jeremyevans.net) diff --git a/frameworks/Ruby/roda-sequel/roda-sequel-postgres-passenger-mri.dockerfile b/frameworks/Ruby/roda-sequel/roda-sequel-postgres-passenger-mri.dockerfile index b3f87e9c742..e060497ea57 100644 --- a/frameworks/Ruby/roda-sequel/roda-sequel-postgres-passenger-mri.dockerfile +++ b/frameworks/Ruby/roda-sequel/roda-sequel-postgres-passenger-mri.dockerfile @@ -1,4 +1,4 @@ -FROM ruby:3.3 +FROM ruby:3.4-rc ADD ./ /roda-sequel WORKDIR /roda-sequel diff --git a/frameworks/Ruby/sinatra-sequel/sinatra-sequel-postgres-passenger-mri.dockerfile b/frameworks/Ruby/sinatra-sequel/sinatra-sequel-postgres-passenger-mri.dockerfile index 5651c491808..a7080367514 100644 --- a/frameworks/Ruby/sinatra-sequel/sinatra-sequel-postgres-passenger-mri.dockerfile +++ b/frameworks/Ruby/sinatra-sequel/sinatra-sequel-postgres-passenger-mri.dockerfile @@ -1,4 +1,4 @@ -FROM ruby:3.3 +FROM ruby:3.4-rc ENV RUBY_YJIT_ENABLE=1 diff --git a/frameworks/Ruby/sinatra/sinatra-postgres-passenger-mri.dockerfile b/frameworks/Ruby/sinatra/sinatra-postgres-passenger-mri.dockerfile index 2a09b22aeba..5d1f93bcb10 100644 --- a/frameworks/Ruby/sinatra/sinatra-postgres-passenger-mri.dockerfile +++ b/frameworks/Ruby/sinatra/sinatra-postgres-passenger-mri.dockerfile @@ -1,4 +1,4 @@ -FROM ruby:3.3 +FROM ruby:3.4-rc ENV RUBY_YJIT_ENABLE=1 From 7a110fbf19c66af2d3bcf6b3f9f4be8efc2f7d22 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 4 Nov 2024 10:47:48 -0800 Subject: [PATCH 202/204] Bump io.undertow:undertow-core in /frameworks/Java/light-java (#9365) Bumps [io.undertow:undertow-core](https://github.com/undertow-io/undertow) from 2.3.15.Final to 2.3.17.Final. - [Release notes](https://github.com/undertow-io/undertow/releases) - [Commits](https://github.com/undertow-io/undertow/compare/2.3.15.Final...2.3.17.Final) --- updated-dependencies: - dependency-name: io.undertow:undertow-core dependency-type: direct:production ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- frameworks/Java/light-java/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frameworks/Java/light-java/pom.xml b/frameworks/Java/light-java/pom.xml index 787dc1253bb..bead4b9f0e9 100644 --- a/frameworks/Java/light-java/pom.xml +++ b/frameworks/Java/light-java/pom.xml @@ -25,7 +25,7 @@ 11 2.0.1 1.3.12 - 2.3.15.Final + 2.3.17.Final 3.3.1 8.0.28 42.7.2 From 67f6e4a9ecf60f7c06d16e6ffded5c181560c80c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 4 Nov 2024 23:48:16 +0000 Subject: [PATCH 203/204] Bump github.com/golang-jwt/jwt/v4 in /frameworks/Go/goravel/src/gin Bumps [github.com/golang-jwt/jwt/v4](https://github.com/golang-jwt/jwt) from 4.5.0 to 4.5.1. - [Release notes](https://github.com/golang-jwt/jwt/releases) - [Changelog](https://github.com/golang-jwt/jwt/blob/main/VERSION_HISTORY.md) - [Commits](https://github.com/golang-jwt/jwt/compare/v4.5.0...v4.5.1) --- updated-dependencies: - dependency-name: github.com/golang-jwt/jwt/v4 dependency-type: indirect ... Signed-off-by: dependabot[bot] --- frameworks/Go/goravel/src/gin/go.mod | 2 +- frameworks/Go/goravel/src/gin/go.sum | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/frameworks/Go/goravel/src/gin/go.mod b/frameworks/Go/goravel/src/gin/go.mod index 93ac7f3ec4e..e010a6645c6 100644 --- a/frameworks/Go/goravel/src/gin/go.mod +++ b/frameworks/Go/goravel/src/gin/go.mod @@ -65,7 +65,7 @@ require ( github.com/go-sql-driver/mysql v1.8.1 // indirect github.com/go-stack/stack v1.8.0 // indirect github.com/goccy/go-json v0.10.2 // indirect - github.com/golang-jwt/jwt/v4 v4.5.0 // indirect + github.com/golang-jwt/jwt/v4 v4.5.1 // indirect github.com/golang-jwt/jwt/v5 v5.2.1 // indirect github.com/golang-migrate/migrate/v4 v4.17.1 // indirect github.com/golang-module/carbon/v2 v2.3.12 // indirect diff --git a/frameworks/Go/goravel/src/gin/go.sum b/frameworks/Go/goravel/src/gin/go.sum index 92b222fbcbb..fefa43c5558 100644 --- a/frameworks/Go/goravel/src/gin/go.sum +++ b/frameworks/Go/goravel/src/gin/go.sum @@ -287,8 +287,9 @@ github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang-jwt/jwt/v4 v4.0.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= github.com/golang-jwt/jwt/v4 v4.4.3/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= -github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg= github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= +github.com/golang-jwt/jwt/v4 v4.5.1 h1:JdqV9zKUdtaa9gdPlywC3aeoEsR681PlKC+4F5gQgeo= +github.com/golang-jwt/jwt/v4 v4.5.1/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= github.com/golang-jwt/jwt/v5 v5.0.0/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= github.com/golang-jwt/jwt/v5 v5.2.1 h1:OuVbFODueb089Lh128TAcimifWaLhJwVflnrgM17wHk= github.com/golang-jwt/jwt/v5 v5.2.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= From cb32cca9ce6926cb7913b6d2d380d199b8fb0666 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 7 Nov 2024 18:04:37 +0000 Subject: [PATCH 204/204] Bump org.hibernate.validator:hibernate-validator Bumps [org.hibernate.validator:hibernate-validator](https://github.com/hibernate/hibernate-validator) from 6.0.20.Final to 6.2.0.Final. - [Changelog](https://github.com/hibernate/hibernate-validator/blob/6.2.0.Final/changelog.txt) - [Commits](https://github.com/hibernate/hibernate-validator/compare/6.0.20.Final...6.2.0.Final) --- updated-dependencies: - dependency-name: org.hibernate.validator:hibernate-validator dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- frameworks/Java/ninja-standalone/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frameworks/Java/ninja-standalone/pom.xml b/frameworks/Java/ninja-standalone/pom.xml index b4af584038f..1c3aaafb7ee 100644 --- a/frameworks/Java/ninja-standalone/pom.xml +++ b/frameworks/Java/ninja-standalone/pom.xml @@ -20,7 +20,7 @@ 2.2.220 5.4.24.Final - 6.0.20.Final + 6.2.0.Final 2.3.0 9.4.18.v20190429 8.0.28