| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187 |
- package main
- import (
- "context"
- "fmt"
- "github.com/cloudwego/hertz/pkg/app"
- "github.com/cloudwego/hertz/pkg/app/server"
- "github.com/cloudwego/hertz/pkg/common/config"
- "github.com/cloudwego/hertz/pkg/common/utils"
- "log"
- "math/rand"
- "runtime"
- "sort"
- "strconv"
- "database/sql"
- _ "github.com/go-sql-driver/mysql"
- )
- const (
- // Database
- worldSelect = "SELECT id, randomNumber FROM World WHERE id = ?"
- worldUpdate = "UPDATE World SET randomNumber = ? WHERE id = ?"
- fortuneSelect = "SELECT id, message FROM Fortune;"
- worldRowCount = 10000
- maxConnectionCount = 256
- )
- type World struct {
- Id uint16 `json:"id"`
- RandomNumber uint16 `json:"randomNumber"`
- }
- type Fortune struct {
- Id uint16 `json:"id"`
- Message string `json:"message"`
- }
- type Fortunes []*Fortune
- func (s Fortunes) Len() int { return len(s) }
- func (s Fortunes) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
- type ByMessage struct{ Fortunes }
- func (s ByMessage) Less(i, j int) bool { return s.Fortunes[i].Message < s.Fortunes[j].Message }
- var (
- // Database
- worldStatement *sql.Stmt
- fortuneStatement *sql.Stmt
- updateStatement *sql.Stmt
- )
- func parseQueries(c context.Context, ctx *app.RequestContext) int {
- n, err := strconv.Atoi(ctx.Query("queries"))
- if err != nil {
- n = 1
- } else if n < 1 {
- n = 1
- } else if n > 500 {
- n = 500
- }
- return n
- }
- // / Test 1: JSON serialization
- func json(c context.Context, ctx *app.RequestContext) {
- ctx.JSON(200, utils.H{"message": "Hello, World!"})
- }
- // / Test 2: Single database query
- func db(c context.Context, ctx *app.RequestContext) {
- var world World
- err := worldStatement.QueryRow(rand.Intn(worldRowCount)+1).Scan(&world.Id, &world.RandomNumber)
- if err != nil {
- ctx.AbortWithError(500, err)
- return
- }
- ctx.JSON(200, &world)
- }
- // / Test 3: Multiple database queries
- func dbs(c context.Context, ctx *app.RequestContext) {
- numQueries := parseQueries(c, ctx)
- worlds := make([]World, numQueries)
- for i := 0; i < numQueries; i++ {
- err := worldStatement.QueryRow(rand.Intn(worldRowCount)+1).Scan(&worlds[i].Id, &worlds[i].RandomNumber)
- if err != nil {
- ctx.AbortWithError(500, err)
- return
- }
- }
- ctx.JSON(200, &worlds)
- }
- // / Test 4: Fortunes
- func fortunes(c context.Context, ctx *app.RequestContext) {
- rows, err := fortuneStatement.Query()
- if err != nil {
- ctx.AbortWithError(500, err)
- return
- }
- fortunes := make(Fortunes, 0, 16)
- for rows.Next() { //Fetch rows
- fortune := Fortune{}
- if err := rows.Scan(&fortune.Id, &fortune.Message); err != nil {
- ctx.AbortWithError(500, err)
- return
- }
- fortunes = append(fortunes, &fortune)
- }
- fortunes = append(fortunes, &Fortune{Message: "Additional fortune added at request time."})
- sort.Sort(ByMessage{fortunes})
- ctx.HTML(200, "fortune.html", fortunes)
- }
- // / Test 5: Database updates
- func update(c context.Context, ctx *app.RequestContext) {
- numQueries := parseQueries(c, ctx)
- world := make([]World, numQueries)
- for i := 0; i < numQueries; i++ {
- if err := worldStatement.QueryRow(rand.Intn(worldRowCount)+1).Scan(&world[i].Id, &world[i].RandomNumber); err != nil {
- ctx.AbortWithError(500, err)
- return
- }
- world[i].RandomNumber = uint16(rand.Intn(worldRowCount) + 1)
- if _, err := updateStatement.Exec(world[i].RandomNumber, world[i].Id); err != nil {
- ctx.AbortWithError(500, err)
- return
- }
- }
- ctx.JSON(200, world)
- }
- // / Test 6: plaintext
- func plaintext(c context.Context, ctx *app.RequestContext) {
- ctx.String(200, "Hello, World!")
- }
- func main() {
- h := server.New(config.Option{F: func(o *config.Options) {
- o.Addr = ":8080"
- },
- })
- serverHeader := []string{"Hertz"}
- h.Use(func(c context.Context, ctx *app.RequestContext) {
- ctx.Header("Server", serverHeader[0])
- })
- h.LoadHTMLGlob("/templates/fortune.html")
- h.GET("/json", json)
- h.GET("/db", db)
- h.GET("/dbs", dbs)
- h.GET("/fortunes", fortunes)
- h.GET("/update", update)
- h.GET("/plaintext", plaintext)
- h.Spin()
- }
- func init() {
- runtime.GOMAXPROCS(runtime.NumCPU())
- dsn := "benchmarkdbuser:benchmarkdbpass@tcp(%s:3306)/hello_world"
- dbhost := "tfb-database"
- db, err := sql.Open("mysql", fmt.Sprintf(dsn, dbhost))
- if err != nil {
- log.Fatalf("Error opening database: %v", err)
- }
- db.SetMaxIdleConns(maxConnectionCount)
- worldStatement, err = db.Prepare(worldSelect)
- if err != nil {
- log.Fatal(err)
- }
- fortuneStatement, err = db.Prepare(fortuneSelect)
- if err != nil {
- log.Fatal(err)
- }
- updateStatement, err = db.Prepare(worldUpdate)
- if err != nil {
- log.Fatal(err)
- }
- }
|