Browse Source

Issue #1996: merge fasthttp-mysql and fasthttp-postgresql into fasthttp folder

Aliaksandr Valialkin 9 years ago
parent
commit
e495d29abb

+ 1 - 2
.travis.yml

@@ -56,8 +56,7 @@ env:
     - "TESTDIR=Erlang/misultin"
     - "TESTDIR=Go/beego"
     - "TESTDIR=Go/falcore"
-    - "TESTDIR=Go/fasthttp-mysql"
-    - "TESTDIR=Go/fasthttp-postgresql"
+    - "TESTDIR=Go/fasthttp"
     - "TESTDIR=Go/gin"
     - "TESTDIR=Go/goji"
     - "TESTDIR=Go/go-std-mongodb"

+ 0 - 51
frameworks/Go/fasthttp-mysql/benchmark_config.json

@@ -1,51 +0,0 @@
-{
-  "framework": "fasthttp-mysql",
-  "tests": [{
-    "default": {
-      "setup_file": "setup",
-      "json_url": "/json",
-      "db_url": "/db",
-      "query_url": "/queries?queries=",
-      "fortune_url": "/fortune",
-      "update_url": "/update?queries=",
-      "plaintext_url": "/plaintext",
-      "port": 8080,
-      "approach": "Realistic",
-      "classification": "Platform",
-      "database": "MySQL",
-      "framework": "fasthttp",
-      "language": "Go",
-      "orm": "Raw",
-      "platform": "Go",
-      "webserver": "None",
-      "os": "Linux",
-      "database_os": "Linux",
-      "display_name": "fasthttp-mysql",
-      "notes": "",
-      "versus": "go"
-    },
-    "prefork": {
-      "setup_file": "setup_prefork",
-      "json_url": "/json",
-      "db_url": "/db",
-      "query_url": "/queries?queries=",
-      "fortune_url": "/fortune",
-      "update_url": "/update?queries=",
-      "plaintext_url": "/plaintext",
-      "port": 8080,
-      "approach": "Realistic",
-      "classification": "Platform",
-      "database": "MySQL",
-      "framework": "fasthttp",
-      "language": "Go",
-      "orm": "Raw",
-      "platform": "Go",
-      "webserver": "None",
-      "os": "Linux",
-      "database_os": "Linux",
-      "display_name": "fasthttp-mysql-prefork",
-      "notes": "",
-      "versus": "go"
-    }
-  }]
-}

+ 0 - 3
frameworks/Go/fasthttp-mysql/setup.bat

@@ -1,3 +0,0 @@
-set GOPATH=C:\FrameworkBenchmarks\Go\fasthttp-mysql
-go build -o server
-.\server

+ 0 - 14
frameworks/Go/fasthttp-mysql/setup.sh

@@ -1,14 +0,0 @@
-#!/bin/bash
-
-sed -i 's|tcp(.*:3306)|tcp('"${DBHOST}"':3306)|g' server.go
-
-fw_depends go
-
-go get -u github.com/go-sql-driver/mysql
-go get -u github.com/valyala/fasthttp
-go get -u github.com/valyala/quicktemplate/qtc
-
-rm -f ./server
-go generate
-go build -o server
-./server &

+ 0 - 14
frameworks/Go/fasthttp-mysql/setup_prefork.sh

@@ -1,14 +0,0 @@
-#!/bin/bash
-
-sed -i 's|tcp(.*:3306)|tcp('"${DBHOST}"':3306)|g' server.go
-
-fw_depends go
-
-go get -u github.com/go-sql-driver/mysql
-go get -u github.com/valyala/fasthttp
-go get -u github.com/valyala/quicktemplate/qtc
-
-rm -f ./server
-go generate
-go build -o server
-./server -prefork &

+ 0 - 4
frameworks/Go/fasthttp-mysql/source_code

@@ -1,4 +0,0 @@
-./fasthttp-mysql/server.go
-./fasthttp-mysql/src/
-./fasthttp-mysql/src/templates/
-./fasthttp-mysql/src/templates/fortune.qtpl

+ 0 - 22
frameworks/Go/fasthttp-mysql/src/templates/fortune.qtpl

@@ -1,22 +0,0 @@
-{% code
-type Fortune struct {
-	ID int
-	Message string
-}
-%}
-
-{% func FortunePage(rows []Fortune) %}<!DOCTYPE html>
-<html>
-<head>
-<title>Fortunes</title>
-</head>
-<body>
-<table>
-<tr><th>id</th><th>message</th></tr>
-{% for _, r := range rows %}
-<tr><td>{%d r.ID %}</td><td>{%s r.Message %}</td></tr>
-{% endfor %}
-</table>
-</body>
-</html>
-{% endfunc %}

+ 0 - 16
frameworks/Go/fasthttp-postgresql/README.md

@@ -1,16 +0,0 @@
-# [fasthttp](https://github.com/valyala/fasthttp) (GoLang) Benchmarking Test for postgresql
-
-This is the go portion of a [benchmarking test suite](https://www.techempower.com/benchmarks/) comparing a variety of web development platforms.
-
-"Fasthttp is a fast http package for Go."
-
-# This variant uses Postgres via Jack Christensen's pgx library
-
-## Test URLs
-
-    http://localhost:8080/json
-    http://localhost:8080/db
-    http://localhost:8080/queries?queries=[1-500]
-    http://localhost:8080/fortunes
-    http://localhost:8080/updates?queries=[1-500]
-    http://localhost:8080/plaintext

+ 0 - 51
frameworks/Go/fasthttp-postgresql/benchmark_config.json

@@ -1,51 +0,0 @@
-{
-  "framework": "fasthttp-postgresql",
-  "tests": [{
-    "default": {
-      "setup_file": "setup",
-      "json_url": "/json",
-      "db_url": "/db",
-      "query_url": "/queries?queries=",
-      "fortune_url": "/fortune",
-      "update_url": "/update?queries=",
-      "plaintext_url": "/plaintext",
-      "port": 8080,
-      "approach": "Realistic",
-      "classification": "Platform",
-      "database": "Postgres",
-      "framework": "fasthttp",
-      "language": "Go",
-      "orm": "Raw",
-      "platform": "Go",
-      "webserver": "None",
-      "os": "Linux",
-      "database_os": "Linux",
-      "display_name": "fasthttp-postgresql",
-      "notes": "",
-      "versus": "go"
-    },
-    "prefork": {
-      "setup_file": "setup_prefork",
-      "json_url": "/json",
-      "db_url": "/db",
-      "query_url": "/queries?queries=",
-      "fortune_url": "/fortune",
-      "update_url": "/update?queries=",
-      "plaintext_url": "/plaintext",
-      "port": 8080,
-      "approach": "Realistic",
-      "classification": "Platform",
-      "database": "Postgres",
-      "framework": "fasthttp",
-      "language": "Go",
-      "orm": "Raw",
-      "platform": "Go",
-      "webserver": "None",
-      "os": "Linux",
-      "database_os": "Linux",
-      "display_name": "fasthttp-postgresql-prefork",
-      "notes": "",
-      "versus": "go"
-    }
-  }]
-}

+ 0 - 3
frameworks/Go/fasthttp-postgresql/setup.bat

@@ -1,3 +0,0 @@
-set GOPATH=C:\FrameworkBenchmarks\Go\fasthttp-postgresql
-go build -o server
-.\server

+ 0 - 14
frameworks/Go/fasthttp-postgresql/setup.sh

@@ -1,14 +0,0 @@
-#!/bin/bash
-
-sed -i 's|localhost|'"${DBHOST}"'|g' server.go
-
-fw_depends go
-
-go get -u github.com/jackc/pgx
-go get -u github.com/valyala/fasthttp
-go get -u github.com/valyala/quicktemplate/qtc
-
-rm -f ./server
-go generate
-go build -o server
-./server &

+ 0 - 14
frameworks/Go/fasthttp-postgresql/setup_prefork.sh

@@ -1,14 +0,0 @@
-#!/bin/bash
-
-sed -i 's|localhost|'"${DBHOST}"'|g' server.go
-
-fw_depends go
-
-go get -u github.com/jackc/pgx
-go get -u github.com/valyala/fasthttp
-go get -u github.com/valyala/quicktemplate/qtc
-
-rm -f ./server
-go generate
-go build -o server
-./server -prefork &

+ 0 - 4
frameworks/Go/fasthttp-postgresql/source_code

@@ -1,4 +0,0 @@
-./fasthttp-postgresql/server.go
-./fasthttp-postgresql/src/
-./fasthttp-postgresql/src/templates/
-./fasthttp-postgresql/src/templates/fortune.qtpl

+ 1 - 1
frameworks/Go/fasthttp-mysql/README.md → frameworks/Go/fasthttp/README.md

@@ -1,4 +1,4 @@
-# [fasthttp](https://github.com/valyala/fasthttp) (GoLang) Benchmarking Test for mysql
+# [fasthttp](https://github.com/valyala/fasthttp) (GoLang) Benchmarking Test
 
 This is the go portion of a [benchmarking test suite](https://www.techempower.com/benchmarks/) comparing a variety of web development platforms.
 

+ 97 - 0
frameworks/Go/fasthttp/benchmark_config.json

@@ -0,0 +1,97 @@
+{
+  "framework": "fasthttp",
+  "tests": [{
+    "mysql": {
+      "setup_file": "setup-mysql",
+      "json_url": "/json",
+      "db_url": "/db",
+      "query_url": "/queries?queries=",
+      "fortune_url": "/fortune",
+      "update_url": "/update?queries=",
+      "plaintext_url": "/plaintext",
+      "port": 8080,
+      "approach": "Realistic",
+      "classification": "Platform",
+      "database": "MySQL",
+      "framework": "fasthttp",
+      "language": "Go",
+      "orm": "Raw",
+      "platform": "Go",
+      "webserver": "None",
+      "os": "Linux",
+      "database_os": "Linux",
+      "display_name": "fasthttp-mysql",
+      "notes": "",
+      "versus": "go"
+    },
+    "mysql-prefork": {
+      "setup_file": "setup-mysql-prefork",
+      "json_url": "/json",
+      "db_url": "/db",
+      "query_url": "/queries?queries=",
+      "fortune_url": "/fortune",
+      "update_url": "/update?queries=",
+      "plaintext_url": "/plaintext",
+      "port": 8080,
+      "approach": "Realistic",
+      "classification": "Platform",
+      "database": "MySQL",
+      "framework": "fasthttp",
+      "language": "Go",
+      "orm": "Raw",
+      "platform": "Go",
+      "webserver": "None",
+      "os": "Linux",
+      "database_os": "Linux",
+      "display_name": "fasthttp-mysql-prefork",
+      "notes": "",
+      "versus": "go"
+    }
+    "postgresql": {
+      "setup_file": "setup-postgresql",
+      "json_url": "/json",
+      "db_url": "/db",
+      "query_url": "/queries?queries=",
+      "fortune_url": "/fortune",
+      "update_url": "/update?queries=",
+      "plaintext_url": "/plaintext",
+      "port": 8080,
+      "approach": "Realistic",
+      "classification": "Platform",
+      "database": "Postgresql",
+      "framework": "fasthttp",
+      "language": "Go",
+      "orm": "Raw",
+      "platform": "Go",
+      "webserver": "None",
+      "os": "Linux",
+      "database_os": "Linux",
+      "display_name": "fasthttp-postgresql",
+      "notes": "",
+      "versus": "go"
+    },
+    "postgresql-prefork": {
+      "setup_file": "setup-postgresql-prefork",
+      "json_url": "/json",
+      "db_url": "/db",
+      "query_url": "/queries?queries=",
+      "fortune_url": "/fortune",
+      "update_url": "/update?queries=",
+      "plaintext_url": "/plaintext",
+      "port": 8080,
+      "approach": "Realistic",
+      "classification": "Platform",
+      "database": "Postgresql",
+      "framework": "fasthttp",
+      "language": "Go",
+      "orm": "Raw",
+      "platform": "Go",
+      "webserver": "None",
+      "os": "Linux",
+      "database_os": "Linux",
+      "display_name": "fasthttp-postgresql-prefork",
+      "notes": "",
+      "versus": "go"
+    }
+  }]
+}

+ 14 - 0
frameworks/Go/fasthttp/setup-mysql-prefork.sh

@@ -0,0 +1,14 @@
+#!/bin/bash
+
+sed -i 's|tcp(.*:3306)|tcp('"${DBHOST}"':3306)|g' src/server-mysql/server.go
+
+fw_depends go
+
+GOPATH=`pwd` go get -u github.com/go-sql-driver/mysql
+GOPATH=`pwd` go get -u github.com/valyala/fasthttp
+GOPATH=`pwd` go get -u github.com/valyala/quicktemplate/qtc
+
+rm -f ./server-mysql
+GOPATH=`pwd` go generate templates
+GOPATH=`pwd` go build server-mysql
+./server-mysql -prefork &

+ 14 - 0
frameworks/Go/fasthttp/setup-mysql.sh

@@ -0,0 +1,14 @@
+#!/bin/bash
+
+sed -i 's|tcp(.*:3306)|tcp('"${DBHOST}"':3306)|g' src/server-mysql/server.go
+
+fw_depends go
+
+GOPATH=`pwd` go get -u github.com/go-sql-driver/mysql
+GOPATH=`pwd` go get -u github.com/valyala/fasthttp
+GOPATH=`pwd` go get -u github.com/valyala/quicktemplate/qtc
+
+rm -f ./server-mysql
+GOPATH=`pwd` go generate templates
+GOPATH=`pwd` go build server-mysql
+./server-mysql &

+ 14 - 0
frameworks/Go/fasthttp/setup-postgresql-prefork.sh

@@ -0,0 +1,14 @@
+#!/bin/bash
+
+sed -i 's|localhost|'"${DBHOST}"'|g' src/server-postgresql/server.go
+
+fw_depends go
+
+GOPATH=`pwd` go get -u github.com/jackc/pgx
+GOPATH=`pwd` go get -u github.com/valyala/fasthttp
+GOPATH=`pwd` go get -u github.com/valyala/quicktemplate/qtc
+
+rm -f ./server-postgresql
+GOPATH=`pwd` go generate templates
+GOPATH=`pwd` go build server-postgresql
+./server-postgresql -prefork &

+ 14 - 0
frameworks/Go/fasthttp/setup-postgresql.sh

@@ -0,0 +1,14 @@
+#!/bin/bash
+
+sed -i 's|localhost|'"${DBHOST}"'|g' src/server-postgresql/server.go
+
+fw_depends go
+
+GOPATH=`pwd` go get -u github.com/jackc/pgx
+GOPATH=`pwd` go get -u github.com/valyala/fasthttp
+GOPATH=`pwd` go get -u github.com/valyala/quicktemplate/qtc
+
+rm -f ./server-postgresql
+GOPATH=`pwd` go generate templates
+GOPATH=`pwd` go build server-postgresql
+./server-postgresql &

+ 3 - 0
frameworks/Go/fasthttp/setup.bat

@@ -0,0 +1,3 @@
+set GOPATH=C:\FrameworkBenchmarks\Go\fasthttp
+go build server-mysql
+.\server-mysql

+ 8 - 0
frameworks/Go/fasthttp/source_code

@@ -0,0 +1,8 @@
+./fasthttp/server.go
+./fasthttp/src/
+./fasthttp/src/common/common.go
+./fasthttp/src/server-mysql/server.go
+./fasthttp/src/server-postgresql/server.go
+./fasthttp/src/templates/
+./fasthttp/src/templates/aux.go
+./fasthttp/src/templates/fortune.qtpl

+ 123 - 0
frameworks/Go/fasthttp/src/common/common.go

@@ -0,0 +1,123 @@
+package common
+
+import (
+	"encoding/json"
+	"flag"
+	"log"
+	"math/rand"
+	"net"
+	"os"
+	"os/exec"
+	"runtime"
+	"sync"
+
+	"github.com/valyala/fasthttp"
+	"github.com/valyala/fasthttp/reuseport"
+
+	"templates"
+)
+
+const worldRowCount = 10000
+
+type JSONResponse struct {
+	Message string `json:"message"`
+}
+
+type World struct {
+	Id           int32 `json:"id"`
+	RandomNumber int32 `json:"randomNumber"`
+}
+
+var (
+	listenAddr = flag.String("listenAddr", ":8080", "Address to listen to")
+	Prefork    = flag.Bool("prefork", false, "use prefork")
+	child      = flag.Bool("child", false, "is child proc")
+)
+
+func JSONHandler(ctx *fasthttp.RequestCtx) {
+	r := jsonResponsePool.Get().(*JSONResponse)
+	r.Message = "Hello, World!"
+	JSONMarshal(ctx, r)
+	jsonResponsePool.Put(r)
+}
+
+var jsonResponsePool = &sync.Pool{
+	New: func() interface{} {
+		return &JSONResponse{}
+	},
+}
+
+func PlaintextHandler(ctx *fasthttp.RequestCtx) {
+	ctx.SetContentType("text/plain")
+	ctx.WriteString("Hello, World!")
+}
+
+func JSONMarshal(ctx *fasthttp.RequestCtx, v interface{}) {
+	ctx.SetContentType("application/json")
+	if err := json.NewEncoder(ctx).Encode(v); err != nil {
+		log.Fatalf("error in json.Encoder.Encode: %s", err)
+	}
+}
+
+func RandomWorldNum() int {
+	return rand.Intn(worldRowCount) + 1
+}
+
+func GetQueriesCount(ctx *fasthttp.RequestCtx) int {
+	n := ctx.QueryArgs().GetUintOrZero("queries")
+	if n < 1 {
+		n = 1
+	} else if n > 500 {
+		n = 500
+	}
+	return n
+}
+
+type FortunesByMessage []templates.Fortune
+
+func (s FortunesByMessage) Len() int           { return len(s) }
+func (s FortunesByMessage) Swap(i, j int)      { s[i], s[j] = s[j], s[i] }
+func (s FortunesByMessage) Less(i, j int) bool { return s[i].Message < s[j].Message }
+
+type WorldsByID []World
+
+func (w WorldsByID) Len() int           { return len(w) }
+func (w WorldsByID) Swap(i, j int)      { w[i], w[j] = w[j], w[i] }
+func (w WorldsByID) Less(i, j int) bool { return w[i].Id < w[j].Id }
+
+func GetListener() net.Listener {
+	if !*Prefork {
+		runtime.GOMAXPROCS(runtime.NumCPU())
+		ln, err := net.Listen("tcp4", *listenAddr)
+		if err != nil {
+			log.Fatal(err)
+		}
+		return ln
+	}
+
+	if !*child {
+		children := make([]*exec.Cmd, runtime.NumCPU())
+		for i := range children {
+			children[i] = exec.Command(os.Args[0], "-prefork", "-child")
+			children[i].Stdout = os.Stdout
+			children[i].Stderr = os.Stderr
+			if err := children[i].Start(); err != nil {
+				log.Fatal(err)
+			}
+		}
+		for _, ch := range children {
+			if err := ch.Wait(); err != nil {
+				log.Print(err)
+			}
+		}
+		os.Exit(0)
+		panic("unreachable")
+	}
+
+	runtime.GOMAXPROCS(1)
+	ln, err := reuseport.Listen("tcp4", *listenAddr)
+	if err != nil {
+		log.Fatal(err)
+	}
+	return ln
+}

+ 18 - 137
frameworks/Go/fasthttp-mysql/server.go → frameworks/Go/fasthttp/src/server-mysql/server.go

@@ -1,38 +1,21 @@
-//go:generate qtc -dir=src/templates
 package main
 
 import (
 	"database/sql"
-	"encoding/json"
 	"flag"
 	"log"
-	"math/rand"
-	"net"
-	"os"
-	"os/exec"
 	"runtime"
 	"sort"
-	"sync"
 
 	_ "github.com/go-sql-driver/mysql"
 	"github.com/valyala/fasthttp"
-	"github.com/valyala/fasthttp/reuseport"
 
+	"common"
 	"templates"
 )
 
-type JSONResponse struct {
-	Message string `json:"message"`
-}
-
-type World struct {
-	Id           uint16 `json:"id"`
-	RandomNumber uint16 `json:"randomNumber"`
-}
-
 const (
 	connectionString   = "benchmarkdbuser:benchmarkdbpass@tcp(localhost:3306)/hello_world"
-	worldRowCount      = 10000
 	maxConnectionCount = 40
 )
 
@@ -44,12 +27,6 @@ var (
 	db *sql.DB
 )
 
-var (
-	listenAddr = flag.String("listenAddr", ":8080", "Address to listen to")
-	prefork    = flag.Bool("prefork", false, "use prefork")
-	child      = flag.Bool("child", false, "is child proc")
-)
-
 func main() {
 	flag.Parse()
 
@@ -62,7 +39,7 @@ func main() {
 	}
 
 	dbConnCount := maxConnectionCount
-	if *prefork {
+	if *common.Prefork {
 		dbConnCount = (dbConnCount + runtime.NumCPU() - 1) / runtime.NumCPU()
 	}
 	db.SetMaxIdleConns(dbConnCount)
@@ -76,7 +53,7 @@ func main() {
 		Handler: mainHandler,
 		Name:    "go",
 	}
-	ln := getListener()
+	ln := common.GetListener()
 	if err = s.Serve(ln); err != nil {
 		log.Fatalf("Error when serving incoming connections: %s", err)
 	}
@@ -86,9 +63,9 @@ func mainHandler(ctx *fasthttp.RequestCtx) {
 	path := ctx.Path()
 	switch string(path) {
 	case "/plaintext":
-		plaintextHandler(ctx)
+		common.PlaintextHandler(ctx)
 	case "/json":
-		jsonHandler(ctx)
+		common.JSONHandler(ctx)
 	case "/db":
 		dbHandler(ctx)
 	case "/queries":
@@ -102,40 +79,21 @@ func mainHandler(ctx *fasthttp.RequestCtx) {
 	}
 }
 
-// Test 1: JSON serialization
-func jsonHandler(ctx *fasthttp.RequestCtx) {
-	r := jsonResponsePool.Get().(*JSONResponse)
-	r.Message = "Hello, World!"
-	jsonMarshal(ctx, r)
-	jsonResponsePool.Put(r)
-}
-
-var jsonResponsePool = &sync.Pool{
-	New: func() interface{} {
-		return &JSONResponse{}
-	},
-}
-
-// Test 2: Single database query
 func dbHandler(ctx *fasthttp.RequestCtx) {
-	var w World
+	var w common.World
 	fetchRandomWorld(&w)
-	jsonMarshal(ctx, &w)
+	common.JSONMarshal(ctx, &w)
 }
 
-// Test 3: Multiple database queries
 func queriesHandler(ctx *fasthttp.RequestCtx) {
-	n := getQueriesCount(ctx)
-
-	worlds := make([]World, n)
+	n := common.GetQueriesCount(ctx)
+	worlds := make([]common.World, n)
 	for i := 0; i < n; i++ {
 		fetchRandomWorld(&worlds[i])
 	}
-
-	jsonMarshal(ctx, worlds)
+	common.JSONMarshal(ctx, worlds)
 }
 
-// Test 4: Fortunes
 func fortuneHandler(ctx *fasthttp.RequestCtx) {
 	rows, err := fortuneSelectStmt.Query()
 	if err != nil {
@@ -153,25 +111,24 @@ func fortuneHandler(ctx *fasthttp.RequestCtx) {
 	rows.Close()
 	fortunes = append(fortunes, templates.Fortune{Message: "Additional fortune added at request time."})
 
-	sort.Sort(FortunesByMessage(fortunes))
+	sort.Sort(common.FortunesByMessage(fortunes))
 
 	ctx.SetContentType("text/html; charset=utf-8")
 	templates.WriteFortunePage(ctx, fortunes)
 }
 
-// Test 5: Database updates
 func updateHandler(ctx *fasthttp.RequestCtx) {
-	n := getQueriesCount(ctx)
+	n := common.GetQueriesCount(ctx)
 
-	worlds := make([]World, n)
+	worlds := make([]common.World, n)
 	for i := 0; i < n; i++ {
 		w := &worlds[i]
 		fetchRandomWorld(w)
-		w.RandomNumber = uint16(randomWorldNum())
+		w.RandomNumber = int32(common.RandomWorldNum())
 	}
 
 	// sorting is required for insert deadlock prevention.
-	sort.Sort(WorldsByID(worlds))
+	sort.Sort(common.WorldsByID(worlds))
 	txn, err := db.Begin()
 	if err != nil {
 		log.Fatalf("Error starting transaction: %s", err)
@@ -187,55 +144,16 @@ func updateHandler(ctx *fasthttp.RequestCtx) {
 		log.Fatalf("Error when commiting world rows: %s", err)
 	}
 
-	jsonMarshal(ctx, worlds)
-}
-
-// Test 6: Plaintext
-func plaintextHandler(ctx *fasthttp.RequestCtx) {
-	ctx.SetContentType("text/plain")
-	ctx.WriteString("Hello, World!")
+	common.JSONMarshal(ctx, worlds)
 }
 
-func jsonMarshal(ctx *fasthttp.RequestCtx, v interface{}) {
-	ctx.SetContentType("application/json")
-	if err := json.NewEncoder(ctx).Encode(v); err != nil {
-		log.Fatalf("error in json.Encoder.Encode: %s", err)
-	}
-}
-
-func fetchRandomWorld(w *World) {
-	n := randomWorldNum()
+func fetchRandomWorld(w *common.World) {
+	n := common.RandomWorldNum()
 	if err := worldSelectStmt.QueryRow(n).Scan(&w.Id, &w.RandomNumber); err != nil {
 		log.Fatalf("Error scanning world row: %s", err)
 	}
 }
 
-func randomWorldNum() int {
-	return rand.Intn(worldRowCount) + 1
-}
-
-func getQueriesCount(ctx *fasthttp.RequestCtx) int {
-	n := ctx.QueryArgs().GetUintOrZero("queries")
-	if n < 1 {
-		n = 1
-	} else if n > 500 {
-		n = 500
-	}
-	return n
-}
-
-type FortunesByMessage []templates.Fortune
-
-func (s FortunesByMessage) Len() int           { return len(s) }
-func (s FortunesByMessage) Swap(i, j int)      { s[i], s[j] = s[j], s[i] }
-func (s FortunesByMessage) Less(i, j int) bool { return s[i].Message < s[j].Message }
-
-type WorldsByID []World
-
-func (w WorldsByID) Len() int           { return len(w) }
-func (w WorldsByID) Swap(i, j int)      { w[i], w[j] = w[j], w[i] }
-func (w WorldsByID) Less(i, j int) bool { return w[i].Id < w[j].Id }
-
 func mustPrepare(db *sql.DB, query string) *sql.Stmt {
 	stmt, err := db.Prepare(query)
 	if err != nil {
@@ -243,40 +161,3 @@ func mustPrepare(db *sql.DB, query string) *sql.Stmt {
 	}
 	return stmt
 }
-
-func getListener() net.Listener {
-	if !*prefork {
-		runtime.GOMAXPROCS(runtime.NumCPU())
-		ln, err := net.Listen("tcp4", *listenAddr)
-		if err != nil {
-			log.Fatal(err)
-		}
-		return ln
-	}
-
-	if !*child {
-		children := make([]*exec.Cmd, runtime.NumCPU())
-		for i := range children {
-			children[i] = exec.Command(os.Args[0], "-prefork", "-child")
-			children[i].Stdout = os.Stdout
-			children[i].Stderr = os.Stderr
-			if err := children[i].Start(); err != nil {
-				log.Fatal(err)
-			}
-		}
-		for _, ch := range children {
-			if err := ch.Wait(); err != nil {
-				log.Print(err)
-			}
-		}
-		os.Exit(0)
-		panic("unreachable")
-	}
-
-	runtime.GOMAXPROCS(1)
-	ln, err := reuseport.Listen("tcp4", *listenAddr)
-	if err != nil {
-		log.Fatal(err)
-	}
-	return ln
-}

+ 21 - 145
frameworks/Go/fasthttp-postgresql/server.go → frameworks/Go/fasthttp/src/server-postgresql/server.go

@@ -1,39 +1,20 @@
-//go:generate qtc -dir=src/templates
 package main
 
 import (
-	"encoding/json"
 	"flag"
 	"fmt"
 	"log"
-	"math/rand"
-	"net"
-	"os"
-	"os/exec"
 	"runtime"
 	"sort"
-	"sync"
 
 	"github.com/jackc/pgx"
 	"github.com/valyala/fasthttp"
-	"github.com/valyala/fasthttp/reuseport"
 
+	"common"
 	"templates"
 )
 
-type JSONResponse struct {
-	Message string `json:"message"`
-}
-
-type World struct {
-	Id           int32 `json:"id"`
-	RandomNumber int32 `json:"randomNumber"`
-}
-
-const (
-	worldRowCount      = 10000
-	maxConnectionCount = 40
-)
+const maxConnectionCount = 40
 
 var (
 	worldSelectStmt   *pgx.PreparedStatement
@@ -43,20 +24,13 @@ var (
 	db *pgx.ConnPool
 )
 
-var (
-	listenAddr = flag.String("listenAddr", ":8080", "Address to listen to")
-	prefork    = flag.Bool("prefork", false, "use prefork")
-	child      = flag.Bool("child", false, "is child proc")
-)
-
 func main() {
 	flag.Parse()
 
 	var err error
 
-	// initialize the connection pool
 	dbConns := maxConnectionCount
-	if *prefork {
+	if *common.Prefork {
 		dbConns = (maxConnectionCount + runtime.NumCPU() - 1) / runtime.NumCPU()
 	}
 	if db, err = initDatabase("localhost", "benchmarkdbuser", "benchmarkdbpass", "hello_world", 5432, dbConns); err != nil {
@@ -67,7 +41,7 @@ func main() {
 		Handler: mainHandler,
 		Name:    "go",
 	}
-	ln := getListener()
+	ln := common.GetListener()
 	if err = s.Serve(ln); err != nil {
 		log.Fatalf("Error when serving incoming connections: %s", err)
 	}
@@ -77,9 +51,9 @@ func mainHandler(ctx *fasthttp.RequestCtx) {
 	path := ctx.Path()
 	switch string(path) {
 	case "/plaintext":
-		plaintextHandler(ctx)
+		common.PlaintextHandler(ctx)
 	case "/json":
-		jsonHandler(ctx)
+		common.JSONHandler(ctx)
 	case "/db":
 		dbHandler(ctx)
 	case "/queries":
@@ -93,40 +67,21 @@ func mainHandler(ctx *fasthttp.RequestCtx) {
 	}
 }
 
-// Test 1: JSON serialization
-func jsonHandler(ctx *fasthttp.RequestCtx) {
-	r := jsonResponsePool.Get().(*JSONResponse)
-	r.Message = "Hello, World!"
-	jsonMarshal(ctx, r)
-	jsonResponsePool.Put(r)
-}
-
-var jsonResponsePool = &sync.Pool{
-	New: func() interface{} {
-		return &JSONResponse{}
-	},
-}
-
-// Test 2: Single database query
 func dbHandler(ctx *fasthttp.RequestCtx) {
-	var w World
+	var w common.World
 	fetchRandomWorld(&w)
-	jsonMarshal(ctx, &w)
+	common.JSONMarshal(ctx, &w)
 }
 
-// Test 3: Multiple database queries
 func queriesHandler(ctx *fasthttp.RequestCtx) {
-	n := getQueriesCount(ctx)
-
-	worlds := make([]World, n)
+	n := common.GetQueriesCount(ctx)
+	worlds := make([]common.World, n)
 	for i := 0; i < n; i++ {
 		fetchRandomWorld(&worlds[i])
 	}
-
-	jsonMarshal(ctx, worlds)
+	common.JSONMarshal(ctx, worlds)
 }
 
-// Test 4: Fortunes
 func fortuneHandler(ctx *fasthttp.RequestCtx) {
 	rows, err := db.Query("fortuneSelectStmt")
 	if err != nil {
@@ -144,25 +99,24 @@ func fortuneHandler(ctx *fasthttp.RequestCtx) {
 	rows.Close()
 	fortunes = append(fortunes, templates.Fortune{Message: "Additional fortune added at request time."})
 
-	sort.Sort(FortunesByMessage(fortunes))
+	sort.Sort(common.FortunesByMessage(fortunes))
 
 	ctx.SetContentType("text/html; charset=utf-8")
 	templates.WriteFortunePage(ctx, fortunes)
 }
 
-// Test 5: Database updates
 func updateHandler(ctx *fasthttp.RequestCtx) {
-	n := getQueriesCount(ctx)
+	n := common.GetQueriesCount(ctx)
 
-	worlds := make([]World, n)
+	worlds := make([]common.World, n)
 	for i := 0; i < n; i++ {
 		w := &worlds[i]
 		fetchRandomWorld(w)
-		w.RandomNumber = int32(randomWorldNum())
+		w.RandomNumber = int32(common.RandomWorldNum())
 	}
 
 	// sorting is required for insert deadlock prevention.
-	sort.Sort(WorldsByID(worlds))
+	sort.Sort(common.WorldsByID(worlds))
 	txn, err := db.Begin()
 	if err != nil {
 		log.Fatalf("Error starting transaction: %s", err)
@@ -178,56 +132,16 @@ func updateHandler(ctx *fasthttp.RequestCtx) {
 		log.Fatalf("Error when commiting world rows: %s", err)
 	}
 
-	jsonMarshal(ctx, worlds)
-}
-
-// Test 6: Plaintext
-func plaintextHandler(ctx *fasthttp.RequestCtx) {
-	ctx.SetContentType("text/plain")
-	ctx.WriteString("Hello, World!")
+	common.JSONMarshal(ctx, worlds)
 }
 
-func jsonMarshal(ctx *fasthttp.RequestCtx, v interface{}) {
-	ctx.SetContentType("application/json")
-	if err := json.NewEncoder(ctx).Encode(v); err != nil {
-		log.Fatalf("error in json.Encoder.Encode: %s", err)
-	}
-}
-
-func fetchRandomWorld(w *World) {
-	n := randomWorldNum()
-
+func fetchRandomWorld(w *common.World) {
+	n := common.RandomWorldNum()
 	if err := db.QueryRow("worldSelectStmt", n).Scan(&w.Id, &w.RandomNumber); err != nil {
 		log.Fatalf("Error scanning world row: %s", err)
 	}
 }
 
-func randomWorldNum() int {
-	return rand.Intn(worldRowCount) + 1
-}
-
-func getQueriesCount(ctx *fasthttp.RequestCtx) int {
-	n := ctx.QueryArgs().GetUintOrZero("queries")
-	if n < 1 {
-		n = 1
-	} else if n > 500 {
-		n = 500
-	}
-	return n
-}
-
-type FortunesByMessage []templates.Fortune
-
-func (s FortunesByMessage) Len() int           { return len(s) }
-func (s FortunesByMessage) Swap(i, j int)      { s[i], s[j] = s[j], s[i] }
-func (s FortunesByMessage) Less(i, j int) bool { return s[i].Message < s[j].Message }
-
-type WorldsByID []World
-
-func (w WorldsByID) Len() int           { return len(w) }
-func (w WorldsByID) Swap(i, j int)      { w[i], w[j] = w[j], w[i] }
-func (w WorldsByID) Less(i, j int) bool { return w[i].Id < w[j].Id }
-
 func mustPrepare(db *pgx.Conn, name, query string) *pgx.PreparedStatement {
 	stmt, err := db.Prepare(name, query)
 	if err != nil {
@@ -236,43 +150,6 @@ func mustPrepare(db *pgx.Conn, name, query string) *pgx.PreparedStatement {
 	return stmt
 }
 
-func getListener() net.Listener {
-	if !*prefork {
-		runtime.GOMAXPROCS(runtime.NumCPU())
-		ln, err := net.Listen("tcp4", *listenAddr)
-		if err != nil {
-			log.Fatal(err)
-		}
-		return ln
-	}
-
-	if !*child {
-		children := make([]*exec.Cmd, runtime.NumCPU())
-		for i := range children {
-			children[i] = exec.Command(os.Args[0], "-prefork", "-child")
-			children[i].Stdout = os.Stdout
-			children[i].Stderr = os.Stderr
-			if err := children[i].Start(); err != nil {
-				log.Fatal(err)
-			}
-		}
-		for _, ch := range children {
-			if err := ch.Wait(); err != nil {
-				log.Print(err)
-			}
-		}
-		os.Exit(0)
-		panic("unreachable")
-	}
-
-	runtime.GOMAXPROCS(1)
-	ln, err := reuseport.Listen("tcp4", *listenAddr)
-	if err != nil {
-		log.Fatal(err)
-	}
-	return ln
-}
-
 func initDatabase(dbHost string, dbUser string, dbPass string, dbName string, dbPort uint16, maxConnectionsInPool int) (*pgx.ConnPool, error) {
 
 	var successOrFailure string = "OK"
@@ -304,8 +181,8 @@ func initDatabase(dbHost string, dbUser string, dbPass string, dbName string, db
 		log.Println("Connecting to database ", dbName, " as user ", dbUser, ": ", successOrFailure)
 
 		log.Println("Fetching one record to test if db connection is valid...")
-		var w World
-		n := randomWorldNum()
+		var w common.World
+		n := common.RandomWorldNum()
 		if errPing := connPool.QueryRow("worldSelectStmt", n).Scan(&w.Id, &w.RandomNumber); errPing != nil {
 			log.Fatalf("Error scanning world row: %s", errPing)
 		}
@@ -315,5 +192,4 @@ func initDatabase(dbHost string, dbUser string, dbPass string, dbName string, db
 	fmt.Println("--------------------------------------------------------------------------------------------")
 
 	return connPool, err
-
 }

+ 3 - 0
frameworks/Go/fasthttp/src/templates/aux.go

@@ -0,0 +1,3 @@
+package templates
+
+//go:generate qtc

+ 0 - 0
frameworks/Go/fasthttp-postgresql/src/templates/fortune.qtpl → frameworks/Go/fasthttp/src/templates/fortune.qtpl