hello.go 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  1. package main
  2. import (
  3. "database/sql"
  4. "encoding/json"
  5. "html/template"
  6. "log"
  7. "math/rand"
  8. "net/http"
  9. "runtime"
  10. "sort"
  11. "strconv"
  12. _ "github.com/go-sql-driver/mysql"
  13. )
  14. type Message struct {
  15. Message string `json:"message"`
  16. }
  17. type World struct {
  18. Id uint16 `json:"id"`
  19. RandomNumber uint16 `json:"randomNumber"`
  20. }
  21. type Fortune struct {
  22. Id uint16 `json:"id"`
  23. Message string `json:"message"`
  24. }
  25. const (
  26. // Database
  27. connectionString = "benchmarkdbuser:benchmarkdbpass@tcp(localhost:3306)/hello_world"
  28. worldSelect = "SELECT id, randomNumber FROM World WHERE id = ?"
  29. worldUpdate = "UPDATE World SET randomNumber = ? WHERE id = ?"
  30. fortuneSelect = "SELECT id, message FROM Fortune;"
  31. worldRowCount = 10000
  32. maxConnectionCount = 256
  33. helloWorldString = "Hello, World!"
  34. )
  35. var (
  36. // Templates
  37. tmpl = template.Must(template.ParseFiles("templates/layout.html", "templates/fortune.html"))
  38. // Database
  39. worldStatement *sql.Stmt
  40. fortuneStatement *sql.Stmt
  41. updateStatement *sql.Stmt
  42. helloWorldBytes = []byte(helloWorldString)
  43. )
  44. func main() {
  45. runtime.GOMAXPROCS(runtime.NumCPU())
  46. db, err := sql.Open("mysql", connectionString)
  47. if err != nil {
  48. log.Fatalf("Error opening database: %v", err)
  49. }
  50. db.SetMaxIdleConns(maxConnectionCount)
  51. worldStatement, err = db.Prepare(worldSelect)
  52. if err != nil {
  53. log.Fatal(err)
  54. }
  55. fortuneStatement, err = db.Prepare(fortuneSelect)
  56. if err != nil {
  57. log.Fatal(err)
  58. }
  59. updateStatement, err = db.Prepare(worldUpdate)
  60. if err != nil {
  61. log.Fatal(err)
  62. }
  63. http.HandleFunc("/db", dbHandler)
  64. http.HandleFunc("/queries", queriesHandler)
  65. http.HandleFunc("/json", jsonHandler)
  66. http.HandleFunc("/fortune", fortuneHandler)
  67. http.HandleFunc("/update", updateHandler)
  68. http.HandleFunc("/plaintext", plaintextHandler)
  69. http.ListenAndServe(":8080", nil)
  70. }
  71. // Test 1: JSON serialization
  72. func jsonHandler(w http.ResponseWriter, r *http.Request) {
  73. w.Header().Set("Content-Type", "application/javascript")
  74. json.NewEncoder(w).Encode(&Message{helloWorldString})
  75. }
  76. // Test 2: Single database query
  77. func dbHandler(w http.ResponseWriter, r *http.Request) {
  78. var world World
  79. err := worldStatement.QueryRow(rand.Intn(worldRowCount)+1).Scan(&world.Id, &world.RandomNumber)
  80. if err != nil {
  81. log.Fatalf("Error scanning world row: %s", err.Error())
  82. }
  83. w.Header().Set("Content-Type", "application/json")
  84. json.NewEncoder(w).Encode(&world)
  85. }
  86. // Test 3: Multiple database queries
  87. func queriesHandler(w http.ResponseWriter, r *http.Request) {
  88. n := 1
  89. if nStr := r.URL.Query().Get("queries"); len(nStr) > 0 {
  90. n, _ = strconv.Atoi(nStr)
  91. }
  92. if n <= 1 {
  93. dbHandler(w, r)
  94. return
  95. }
  96. world := make([]World, n)
  97. for i := 0; i < n; i++ {
  98. err := worldStatement.QueryRow(rand.Intn(worldRowCount)+1).Scan(&world[i].Id, &world[i].RandomNumber)
  99. if err != nil {
  100. log.Fatalf("Error scanning world row: %s", err.Error())
  101. }
  102. }
  103. w.Header().Set("Content-Type", "application/json")
  104. json.NewEncoder(w).Encode(world)
  105. }
  106. // Test 4: Fortunes
  107. func fortuneHandler(w http.ResponseWriter, r *http.Request) {
  108. rows, err := fortuneStatement.Query()
  109. if err != nil {
  110. log.Fatalf("Error preparing statement: %v", err)
  111. }
  112. fortunes := make(Fortunes, 0, 16)
  113. for rows.Next() { //Fetch rows
  114. fortune := Fortune{}
  115. if err := rows.Scan(&fortune.Id, &fortune.Message); err != nil {
  116. log.Fatalf("Error scanning fortune row: %s", err.Error())
  117. }
  118. fortunes = append(fortunes, &fortune)
  119. }
  120. fortunes = append(fortunes, &Fortune{Message: "Additional fortune added at request time."})
  121. sort.Sort(ByMessage{fortunes})
  122. w.Header().Set("Content-Type", "text/html")
  123. if err := tmpl.Execute(w, fortunes); err != nil {
  124. http.Error(w, err.Error(), http.StatusInternalServerError)
  125. }
  126. }
  127. // Test 5: Database updates
  128. func updateHandler(w http.ResponseWriter, r *http.Request) {
  129. n := 1
  130. if nStr := r.URL.Query().Get("queries"); len(nStr) > 0 {
  131. n, _ = strconv.Atoi(nStr)
  132. }
  133. w.Header().Set("Content-Type", "application/json")
  134. encoder := json.NewEncoder(w)
  135. if n <= 1 {
  136. var world World
  137. worldStatement.QueryRow(rand.Intn(worldRowCount)+1).Scan(&world.Id, &world.RandomNumber)
  138. world.RandomNumber = uint16(rand.Intn(worldRowCount) + 1)
  139. updateStatement.Exec(world.RandomNumber, world.Id)
  140. encoder.Encode(&world)
  141. } else {
  142. world := make([]World, n)
  143. for i := 0; i < n; i++ {
  144. if err := worldStatement.QueryRow(rand.Intn(worldRowCount)+1).Scan(&world[i].Id, &world[i].RandomNumber); err != nil {
  145. log.Fatalf("Error scanning world row: %s", err.Error())
  146. }
  147. world[i].RandomNumber = uint16(rand.Intn(worldRowCount) + 1)
  148. if _, err := updateStatement.Exec(world[i].RandomNumber, world[i].Id); err != nil {
  149. log.Fatalf("Error updating world row: %s", err.Error())
  150. }
  151. }
  152. encoder.Encode(world)
  153. }
  154. }
  155. // Test 6: Plaintext
  156. func plaintextHandler(w http.ResponseWriter, r *http.Request) {
  157. w.Header().Set("Content-Type", "text/plain")
  158. w.Write(helloWorldBytes)
  159. }
  160. type Fortunes []*Fortune
  161. func (s Fortunes) Len() int { return len(s) }
  162. func (s Fortunes) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
  163. type ByMessage struct{ Fortunes }
  164. func (s ByMessage) Less(i, j int) bool { return s.Fortunes[i].Message < s.Fortunes[j].Message }