Browse Source

Add gin framework.

INADA Naoki 11 years ago
parent
commit
45076a2041
5 changed files with 242 additions and 0 deletions
  1. 28 0
      gin/benchmark_config
  2. 14 0
      gin/fortune.html
  3. 178 0
      gin/hello.go
  4. 3 0
      gin/install.sh
  5. 19 0
      gin/setup.py

+ 28 - 0
gin/benchmark_config

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

+ 14 - 0
gin/fortune.html

@@ -0,0 +1,14 @@
+{{define "content"}}
+<table>
+<tr>
+<th>id</th>
+<th>message</th>
+</tr>
+{{range .}}
+<tr>
+<td>{{.Id}}</td>
+<td>{{.Message}}</td>
+</tr>
+{{end}}
+</table>
+{{end}}

+ 178 - 0
gin/hello.go

@@ -0,0 +1,178 @@
+package main
+
+import (
+	"fmt"
+	"log"
+	"math/rand"
+	"os"
+	"runtime"
+	"sort"
+	"strconv"
+
+	"database/sql"
+
+	"github.com/gin-gonic/gin"
+	_ "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 Message struct {
+	Message string `json:"message"`
+}
+
+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 *gin.Context) int {
+	n, err := strconv.Atoi(c.Params.ByName("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 *gin.Context) {
+	c.JSON(200, gin.H{"message": "Hello, World!"})
+}
+
+/// Test 2: Single database query
+func db(c *gin.Context) {
+	var world World
+	err := worldStatement.QueryRow(rand.Intn(worldRowCount)+1).Scan(&world.Id, &world.RandomNumber)
+	if err != nil {
+		c.Fail(500, err)
+	}
+	c.JSON(200, &world)
+}
+
+/// Test 3: Multiple database queries
+func dbs(c *gin.Context) {
+	numQueries := parseQueries(c)
+
+	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 {
+			c.Fail(500, err)
+		}
+	}
+	c.JSON(200, &worlds)
+}
+
+/// Test 4: Fortunes
+func fortunes(c *gin.Context) {
+	rows, err := fortuneStatement.Query()
+	if err != nil {
+		c.Fail(500, err)
+	}
+
+	fortunes := make(Fortunes, 0, 16)
+	for rows.Next() { //Fetch rows
+		fortune := Fortune{}
+		if err := rows.Scan(&fortune.Id, &fortune.Message); err != nil {
+			c.Fail(500, err)
+		}
+		fortunes = append(fortunes, &fortune)
+	}
+	fortunes = append(fortunes, &Fortune{Message: "Additional fortune added at request time."})
+
+	sort.Sort(ByMessage{fortunes})
+	c.HTML(200, "fortune.html", fortunes)
+}
+
+/// Test 5: Database updates
+func update(c *gin.Context) {
+	numQueries := parseQueries(c)
+	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 {
+			c.Fail(500, err)
+		}
+		world[i].RandomNumber = uint16(rand.Intn(worldRowCount) + 1)
+		if _, err := updateStatement.Exec(world[i].RandomNumber, world[i].Id); err != nil {
+			c.Fail(500, err)
+		}
+	}
+	c.JSON(200, world)
+}
+
+/// Test 6: plaintext
+func plaintext(c *gin.Context) {
+	c.String(200, "Hello, World!")
+}
+
+func main() {
+	r := gin.New()
+	r.LoadHTMLFiles("fortune.html")
+	r.GET("/json", json)
+	r.GET("/db", db)
+	r.GET("/dbs", dbs)
+	r.GET("/fortunes", fortunes)
+	r.GET("/update", update)
+	r.GET("/plaintext", plaintext)
+	r.Run(":8080")
+}
+
+func init() {
+	runtime.GOMAXPROCS(runtime.NumCPU())
+
+	dsn := "benchmarkdbuser:benchmarkdbpass@tcp(%s:3306)/hello_world"
+	dbhost := os.Getenv("TFB_DATABASE_HOST")
+	if dbhost == "" {
+		dbhost = "localhost"
+	}
+
+	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)
+	}
+}

+ 3 - 0
gin/install.sh

@@ -0,0 +1,3 @@
+#!/bin/bash
+
+fw_depends go

+ 19 - 0
gin/setup.py

@@ -0,0 +1,19 @@
+import subprocess
+import os
+
+
+def start(args, logfile, errfile):
+    subprocess.call("go get github.com/gin-gonic/gin", shell=True, cwd="gin", stderr=errfile, stdout=logfile) 
+    subprocess.call("go get github.com/go-sql-driver/mysql", shell=True, cwd="gin", stderr=errfile, stdout=logfile) 
+    subprocess.Popen("go run hello.go".rsplit(" "), cwd="gin", stderr=errfile, stdout=logfile)
+    return 0
+
+
+def stop(logfile, errfile):
+    p = subprocess.Popen(['ps', 'aux'], stdout=subprocess.PIPE)
+    out, err = p.communicate()
+    for line in out.splitlines():
+        if 'hello' in line:
+            pid = int(line.split(None, 2)[1])
+            os.kill(pid, 15)
+    return 0