Browse Source

benchmark app updated to latest of aah v0.11.0 (#3916)

- added aah postgresql bench endpoints
- seperated aah mysql bench endpoints
- three env profiles created bm-default, bm-mysql and bm-postgresql
- new docker files added
- readme updated
Jeevanandam M 7 years ago
parent
commit
20a44061e3

+ 20 - 12
frameworks/Go/aah/README.md

@@ -1,18 +1,26 @@
-# [aah framework](https://aahframework.org) Benchmarking Test
+<p align="center">
+  <img src="https://cdn.aahframework.org/assets/img/aah-logo-64x64.png" />
+  <h2 align="center">Benchmark Application</h2>
+  <p align="center">aah - A secure, flexible, rapid Go web framework</p>
+</p>
 
-This is the `Go` portion of a [benchmarking test suite](../) comparing a variety of web development platforms.
+Visit official website https://aahframework.org to learn more about `aah` framework. 
 
-> **aah framework** is a scalable, performant, rapid development Web framework for Go. aah focuses on very small footprint, maintainability, performance, configurability, security and extensibility as application use cases expands.
+### Test URLs
 
-**|**  [Getting started](https://docs.aahframework.org/getting-started.html) **|** [Features](https://aahframework.org/features.html) **|** [Documentation](https://docs.aahframework.org) **|**
-
-Requires ≥ go1.8
+  * http://localhost:8080/json
+  * http://localhost:8080/plaintext
 
-## Test URLs
+### Test URLs - w/ MySQL Datasource
 
-  * http://localhost:8080/json
   * http://localhost:8080/db
-  * http://localhost:8080/queries?count=[1-500]
-  * http://localhost:8080/fortunes
-  * http://localhost:8080/updates?count=[1-500]
-  * http://localhost:8080/plaintext
+  * http://localhost:8080/db/queries?count=[1-500]
+  * http://localhost:8080/db/fortunes
+  * http://localhost:8080/db/updates?count=[1-500]
+  
+### Test URLs - w/ PostgreSQL Datasource
+
+  * http://localhost:8080/pg-db
+  * http://localhost:8080/pg-db/queries?count=[1-500]
+  * http://localhost:8080/pg-db/fortunes
+  * http://localhost:8080/pg-db/updates?count=[1-500]

+ 27 - 0
frameworks/Go/aah/aah-mysql.dockerfile

@@ -0,0 +1,27 @@
+FROM golang:1.10.1
+
+RUN apt update -yqq && apt install unzip
+
+ADD ./ /aah
+WORKDIR /aah
+
+RUN mkdir bin
+ENV GOPATH /aah
+ENV PATH ${GOPATH}/bin:${PATH}
+
+RUN curl -sL -o install_glide.sh https://glide.sh/get
+RUN sh install_glide.sh
+
+WORKDIR src/benchmark
+RUN glide -v
+RUN glide install
+
+RUN curl -sL -o /tmp/aah_linux_amd64.zip  https://aahframework.org/releases/cli/0.12.0/aah_linux_amd64.zip
+RUN unzip -q /tmp/aah_linux_amd64.zip -d ${GOPATH}/bin/
+
+RUN aah -v
+RUN aah -y migrate code
+RUN mkdir -p views/common
+RUN aah build -s
+
+CMD build/bin/benchmark -profile bm_mysql

+ 27 - 0
frameworks/Go/aah/aah-postgresql.dockerfile

@@ -0,0 +1,27 @@
+FROM golang:1.10.1
+
+RUN apt update -yqq && apt install unzip
+
+ADD ./ /aah
+WORKDIR /aah
+
+RUN mkdir bin
+ENV GOPATH /aah
+ENV PATH ${GOPATH}/bin:${PATH}
+
+RUN curl -sL -o install_glide.sh https://glide.sh/get
+RUN sh install_glide.sh
+
+WORKDIR src/benchmark
+RUN glide -v
+RUN glide install
+
+RUN curl -sL -o /tmp/aah_linux_amd64.zip  https://aahframework.org/releases/cli/0.12.0/aah_linux_amd64.zip
+RUN unzip -q /tmp/aah_linux_amd64.zip -d ${GOPATH}/bin/
+
+RUN aah -v
+RUN aah -y migrate code
+RUN mkdir -p views/common
+RUN aah build -s
+
+CMD build/bin/benchmark -profile bm_postgresql

+ 9 - 18
frameworks/Go/aah/aah.dockerfile

@@ -9,28 +9,19 @@ RUN mkdir bin
 ENV GOPATH /aah
 ENV PATH ${GOPATH}/bin:${PATH}
 
-RUN mkdir src/aahframework.org
-RUN git clone https://github.com/go-aah/tools.git src/aahframework.org/tools.v0
-WORKDIR src/aahframework.org/tools.v0
-RUN git checkout tags/v0.8 -b v0.8
-
-WORKDIR /aah
-RUN go get aahframework.org/tools.v0/aah/...
-RUN go install aahframework.org/tools.v0/aah
-RUN aah -v
-
 RUN curl -sL -o install_glide.sh https://glide.sh/get
 RUN sh install_glide.sh
 
+WORKDIR src/benchmark
 RUN glide -v
+RUN glide install
 
-RUN rm -rf src/aahframework.org src/golang.org src/gopkg.in
+RUN curl -sL -o /tmp/aah_linux_amd64.zip  https://aahframework.org/releases/cli/0.12.0/aah_linux_amd64.zip
+RUN unzip -q /tmp/aah_linux_amd64.zip -d ${GOPATH}/bin/
 
-WORKDIR src/benchmark
-RUN glide install
-RUN aah build -o build/benchmark.zip
-WORKDIR build
-RUN unzip benchmark.zip
+RUN aah -v
+RUN aah -y migrate code
+RUN mkdir -p views/common
+RUN aah build -s
 
-WORKDIR /aah/src/benchmark
-CMD build/benchmark/bin/benchmark --profile=prod
+CMD build/bin/benchmark -profile bm_default

+ 45 - 7
frameworks/Go/aah/benchmark_config.json

@@ -3,16 +3,54 @@
   "tests": [{
     "default": {
       "json_url": "/json",
-      "db_url": "/db",
-      "query_url": "/queries?count=",
-      "fortune_url": "/fortunes",
-      "update_url": "/updates?count=",
       "plaintext_url": "/plaintext",
       "port": 8080,
       "approach": "Realistic",
       "classification": "Fullstack",
       "database": "MySQL",
-      "framework": "aah",
+      "framework": "None",
+      "language": "Go",
+      "flavor": "None",
+      "orm": "Raw",
+      "platform": "None",
+      "webserver": "None",
+      "os": "Linux",
+      "database_os": "Linux",
+      "display_name": "aah",
+      "notes": "",
+      "versus": "go"
+    },
+    "mysql": {
+      "db_url": "/db",
+      "query_url": "/db/queries?count=",
+      "fortune_url": "/db/fortunes",
+      "update_url": "/db/updates?count=",
+      "port": 8080,
+      "approach": "Realistic",
+      "classification": "Fullstack",
+      "database": "MySQL",
+      "framework": "None",
+      "language": "Go",
+      "flavor": "None",
+      "orm": "Raw",
+      "platform": "None",
+      "webserver": "None",
+      "os": "Linux",
+      "database_os": "Linux",
+      "display_name": "aah-mysql",
+      "notes": "",
+      "versus": "go"
+    },
+    "postgresql": {
+      "db_url": "/pg-db",
+      "query_url": "/pg-db/queries?count=",
+      "fortune_url": "/pg-db/fortunes",
+      "update_url": "/pg-db/updates?count=",
+      "port": 8080,
+      "approach": "Realistic",
+      "classification": "Fullstack",
+      "database": "Postgres",
+      "framework": "None",
       "language": "Go",
       "flavor": "None",
       "orm": "Raw",
@@ -20,9 +58,9 @@
       "webserver": "None",
       "os": "Linux",
       "database_os": "Linux",
-      "display_name": "aah-framework",
+      "display_name": "aah-postgresql",
       "notes": "",
       "versus": "go"
-    }
+    }  
   }]
 }

+ 68 - 50
frameworks/Go/aah/src/benchmark/app/controllers/app.go

@@ -2,19 +2,13 @@ package controllers
 
 import (
 	"strconv"
-	"strings"
-	"sync"
 
 	"benchmark/app/models"
 
 	"aahframework.org/aah.v0"
-	"aahframework.org/ahttp.v0"
 )
 
-var (
-	helloWorldMsg = "Hello, World!"
-	messagePool   = sync.Pool{New: func() interface{} { return &models.Message{} }}
-)
+const helloWorldString = "Hello, World!"
 
 // AppController struct application controller
 type AppController struct {
@@ -22,61 +16,95 @@ type AppController struct {
 }
 
 // Plaintext method is for `/plaintext` test.
-func (a *AppController) Plaintext() {
-	a.Reply().Text(helloWorldMsg)
+func (c *AppController) Plaintext() {
+	c.Reply().Text(helloWorldString)
 }
 
 // JSON method is for `/json` test.
-func (a *AppController) JSON() {
-	m := messagePool.Get().(*models.Message)
-	m.Message = helloWorldMsg
-	a.Reply().JSON(m)
+func (c *AppController) JSON() {
+	c.Reply().JSON(models.Message{Message: helloWorldString})
 }
 
-// GetWorld returns one world record randomly for `/db` test.
-func (a *AppController) GetWorld() {
+//‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
+// MySQL DB based implementation
+//___________________________________________________________________________
+
+// World returns one world record randomly for `/db` test.
+func (c *AppController) World() {
 	world := new(models.World)
-	if err := models.FetchRandomWorld(world); err != nil {
-		a.Reply().InternalServerError().Text(err.Error())
+	if err := models.MySQLFetchRandomWorld(world); err != nil {
+		c.Reply().InternalServerError().Text(err.Error())
 		return
 	}
-	a.Reply().JSON(world)
+	c.Reply().JSON(world)
 }
 
-// GetWorlds returns one world record randomly for `/queries` test.
-func (a *AppController) GetWorlds() {
-	a.handleResult(models.GetRandomWorlds(a.getCount()))
+// Worlds returns one world record randomly for `/db/queries` test.
+func (c *AppController) Worlds() {
+	c.handleResult(models.MySQLRandomWorlds(c.getCount()))
 }
 
-// UpdateWorlds updates record and returns those records for `/updates` test.
-func (a *AppController) UpdateWorlds() {
-	a.handleResult(models.UpdateRandomWorlds(a.getCount()))
+// UpdateWorlds updates record and returns those records for `/db/updates` test.
+func (c *AppController) UpdateWorlds() {
+	c.handleResult(models.MySQLUpdateRandomWorlds(c.getCount()))
 }
 
-// Fortunes method is for `/fortunes` test.
-func (a *AppController) Fortunes() {
-	fortunes, err := models.GetFortunes()
+// Fortunes method is for `/db/fortunes` test.
+func (c *AppController) Fortunes() {
+	fortunes, err := models.MySQLFortunes()
 	if err != nil {
-		a.Reply().InternalServerError().Text(err.Error())
+		c.Reply().InternalServerError().Text(err.Error())
 		return
 	}
 
-	a.Reply().HTML(aah.Data{
+	c.Reply().HTML(aah.Data{
 		"Fortunes": fortunes,
 	})
 }
 
-// Finally interceptor
-func (a *AppController) Finally() {
-	// TFB requirements
-	// Removing charset for json and plaintext
-	if !strings.HasPrefix(a.Reply().ContType, ahttp.ContentTypeHTML.Mime) {
-		a.Reply().ContType = a.Reply().ContType[:strings.IndexByte(a.Reply().ContType, ';')]
+//‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
+// PostgreSQL DB based implementation
+//___________________________________________________________________________
+
+// PGWorld returns one world record randomly for `/pg-db` test.
+func (c *AppController) PGWorld() {
+	world := new(models.World)
+	if err := models.PGFetchRandomWorld(world); err != nil {
+		c.Reply().InternalServerError().Text(err.Error())
+		return
+	}
+	c.Reply().JSON(world)
+}
+
+// PGWorlds returns one world record randomly for `/pg-db/queries` test.
+func (c *AppController) PGWorlds() {
+	c.handleResult(models.PGRandomWorlds(c.getCount()))
+}
+
+// PGUpdateWorlds updates record and returns those records for `/pg-db/updates` test.
+func (c *AppController) PGUpdateWorlds() {
+	c.handleResult(models.PGUpdateRandomWorlds(c.getCount()))
+}
+
+// PGFortunes method is for `/pg-db/fortunes` test.
+func (c *AppController) PGFortunes() {
+	fortunes, err := models.PGFortunes()
+	if err != nil {
+		c.Reply().InternalServerError().Text(err.Error())
+		return
 	}
+
+	c.Reply().HTMLf("fortunes.html", aah.Data{
+		"Fortunes": fortunes,
+	})
 }
 
-func (a *AppController) getCount() int {
-	cnt, err := strconv.Atoi(a.Req.QueryValue("count"))
+//‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
+// Unexported methods
+//___________________________________________________________________________
+
+func (c *AppController) getCount() int {
+	cnt, err := strconv.Atoi(c.Req.QueryValue("count"))
 	if err != nil || cnt < 1 {
 		cnt = 1
 	} else if cnt > 500 {
@@ -85,20 +113,10 @@ func (a *AppController) getCount() int {
 	return cnt
 }
 
-func (a *AppController) handleResult(worlds *[]models.World, err error) {
+func (c *AppController) handleResult(worlds *[]models.World, err error) {
 	if err != nil {
-		a.Reply().InternalServerError().Text(err.Error())
+		c.Reply().InternalServerError().Text(err.Error())
 		return
 	}
-	a.Reply().JSON(worlds)
-}
-
-// TFB request has incorrect Host header i.e. `Host: TFB-Server`
-// Correct Host header is `Host: TFB-server:8080`
-func onRequestEvent(e *aah.Event) {
-	e.Data.(*aah.Context).Req.Host = "TFB-Server:8080"
-}
-
-func init() {
-	aah.OnRequest(onRequestEvent)
+	c.Reply().JSON(worlds)
 }

+ 0 - 56
frameworks/Go/aah/src/benchmark/app/db/datasource.go

@@ -1,56 +0,0 @@
-package db
-
-import (
-	"database/sql"
-	"fmt"
-	"runtime"
-
-	"aahframework.org/aah.v0"
-	"aahframework.org/log.v0"
-
-	// mysql driver
-	_ "github.com/go-sql-driver/mysql"
-)
-
-var (
-	maxConnsCount = runtime.NumCPU() * 2
-	db            *sql.DB
-)
-
-// DB instance
-func DB() *sql.DB {
-	return db
-}
-
-// DatabaseInit initializes the Database.
-func DatabaseInit(e *aah.Event) {
-	cfg := aah.AppConfig()
-	dbHost := "tfb-database"
-
-	dbURL := fmt.Sprintf(cfg.StringDefault("datasource.benchmark.url", ""), dbHost)
-
-	var err error
-	db, err = sql.Open(cfg.StringDefault("datasource.benchmark.driver", ""), dbURL)
-	if err != nil {
-		log.Fatal(err)
-	}
-
-	if err = db.Ping(); err != nil {
-		log.Fatal(err)
-	}
-
-	db.SetMaxIdleConns(maxConnsCount)
-	db.SetMaxOpenConns(maxConnsCount)
-}
-
-// DatabaseClose initializes the Database.
-func DatabaseClose(e *aah.Event) {
-	if db != nil {
-		_ = db.Close()
-	}
-}
-
-func init() {
-	aah.OnStart(DatabaseInit)
-	aah.OnShutdown(DatabaseClose)
-}

+ 63 - 0
frameworks/Go/aah/src/benchmark/app/db/mysql.go

@@ -0,0 +1,63 @@
+package db
+
+import (
+	"database/sql"
+	"runtime"
+
+	"aahframework.org/aah.v0"
+	"aahframework.org/log.v0"
+
+	// mysql driver
+	_ "github.com/go-sql-driver/mysql"
+)
+
+// MySQL database connection and prepared statements
+var (
+	MySQL               *sql.DB
+	MSworldSelectStmt   *sql.Stmt
+	MSworldUpdateStmt   *sql.Stmt
+	MSfortuneSelectStmt *sql.Stmt
+
+	mysqlMaxConnCount = runtime.NumCPU() * 2
+)
+
+// InitMySQLDatabase initializes the Database.
+func InitMySQLDatabase(_ *aah.Event) {
+	cfg := aah.AppConfig()
+	if aah.AppProfile() != "bm_mysql" {
+		return
+	}
+
+	var err error
+	MySQL, err = sql.Open(
+		cfg.StringDefault("datasource.benchmark.mysql.driver", "mysql"),
+		cfg.StringDefault("datasource.benchmark.mysql.url", ""),
+	)
+	if err != nil {
+		log.Fatal(err)
+	}
+
+	if err = MySQL.Ping(); err != nil {
+		log.Fatal(err)
+	}
+
+	MySQL.SetMaxIdleConns(mysqlMaxConnCount)
+	MySQL.SetMaxOpenConns(mysqlMaxConnCount)
+
+	if MSworldSelectStmt, err = MySQL.Prepare("SELECT id, randomNumber FROM World WHERE id = ?"); err != nil {
+		log.Fatal(err)
+	}
+	if MSworldUpdateStmt, err = MySQL.Prepare("UPDATE World SET randomNumber = ? WHERE id = ?"); err != nil {
+		log.Fatal(err)
+	}
+	if MSfortuneSelectStmt, err = MySQL.Prepare("SELECT id, message FROM Fortune"); err != nil {
+		log.Fatal(err)
+	}
+}
+
+// CloseMySQLDatabase initializes the Database.
+func CloseMySQLDatabase(_ *aah.Event) {
+	if MySQL != nil {
+		_ = MySQL.Close()
+	}
+}

+ 65 - 0
frameworks/Go/aah/src/benchmark/app/db/postgresql.go

@@ -0,0 +1,65 @@
+package db
+
+import (
+	"runtime"
+
+	"aahframework.org/aah.v0"
+	"aahframework.org/log.v0"
+	"github.com/jackc/pgx"
+)
+
+// PostgreSQL database connection and statements
+var (
+	PostgreSQL          *pgx.ConnPool
+	PGWorldSelectStmt   *pgx.PreparedStatement
+	PGWorldUpdateStmt   *pgx.PreparedStatement
+	PGFortuneSelectStmt *pgx.PreparedStatement
+
+	postgresqlMaxConnCount = runtime.NumCPU() * 4
+)
+
+// InitPostgreSQLDatabase initializes the Database.
+func InitPostgreSQLDatabase(_ *aah.Event) {
+	cfg := aah.AppConfig()
+	if aah.AppProfile() != "bm_postgresql" {
+		return
+	}
+
+	config := pgx.ConnPoolConfig{
+		ConnConfig: pgx.ConnConfig{
+			Host:     cfg.StringDefault("datasource.benchmark.postgresql.host", ""),
+			Port:     uint16(cfg.IntDefault("datasource.benchmark.postgresql.port", 5432)),
+			User:     cfg.StringDefault("datasource.benchmark.postgresql.user", ""),
+			Password: cfg.StringDefault("datasource.benchmark.postgresql.password", ""),
+			Database: cfg.StringDefault("datasource.benchmark.postgresql.dbname", ""),
+		},
+		MaxConnections: postgresqlMaxConnCount,
+	}
+
+	config.AfterConnect = func(conn *pgx.Conn) error {
+		var err error
+		if PGWorldSelectStmt, err = conn.Prepare("worldSelectStmt", "SELECT id, randomNumber FROM World WHERE id = $1"); err != nil {
+			log.Fatal(err)
+		}
+		if PGWorldUpdateStmt, err = conn.Prepare("worldUpdateStmt", "UPDATE World SET randomNumber = $1 WHERE id = $2"); err != nil {
+			log.Fatal(err)
+		}
+		if PGFortuneSelectStmt, err = conn.Prepare("fortuneSelectStmt", "SELECT id, message FROM Fortune"); err != nil {
+			log.Fatal(err)
+		}
+		return nil
+	}
+
+	var err error
+	PostgreSQL, err = pgx.NewConnPool(config)
+	if err != nil {
+		log.Fatal(err)
+	}
+}
+
+// ClosePostgreSQLDatabase initializes the Database.
+func ClosePostgreSQLDatabase(_ *aah.Event) {
+	if PostgreSQL != nil {
+		PostgreSQL.Close()
+	}
+}

+ 49 - 0
frameworks/Go/aah/src/benchmark/app/init.go

@@ -0,0 +1,49 @@
+// aah application initialization - configuration, server extensions, middleware's, etc.
+// Customize it per application use case.
+
+package main
+
+import (
+	"benchmark/app/db"
+
+	"aahframework.org/aah.v0"
+)
+
+func init() {
+
+	//‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
+	// Server Extensions
+	// Doc: https://docs.aahframework.org/server-extension.html
+	//
+	// Best Practice: Define a function with meaningful name in a package and
+	// register it here. Extensions function name gets logged in the log,
+	// its very helpful to have meaningful log information.
+	//
+	// Such as:
+	//    - Dedicated package for config loading
+	//    - Dedicated package for datasource connections
+	//    - etc
+	//__________________________________________________________________________
+
+	aah.OnStart(db.InitMySQLDatabase)
+	aah.OnStart(db.InitPostgreSQLDatabase)
+	aah.OnStart(func(_ *aah.Event) {
+		aah.AppSecurityManager().AntiCSRF.Enabled = false
+	})
+
+	aah.OnPostShutdown(db.CloseMySQLDatabase)
+	aah.OnPostShutdown(db.ClosePostgreSQLDatabase)
+
+	//‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
+	// Middleware's
+	// Doc: https://docs.aahframework.org/middleware.html
+	//
+	// Executed in the order they are defined. It is recommended; NOT to change
+	// the order of pre-defined aah framework middleware's.
+	//__________________________________________________________________________
+	aah.AppHTTPEngine().Middlewares(
+		aah.RouteMiddleware,
+		aah.ActionMiddleware,
+	)
+
+}

+ 98 - 50
frameworks/Go/aah/src/benchmark/app/models/models.go

@@ -1,23 +1,14 @@
 package models
 
 import (
-	"benchmark/app/db"
-	"database/sql"
+	"fmt"
 	"math/rand"
 	"sort"
 
-	"aahframework.org/aah.v0"
-	"aahframework.org/log.v0"
+	"benchmark/app/db"
 )
 
-var (
-	// Prepare statements
-	worldSelectStmt   *sql.Stmt
-	worldUpdateStmt   *sql.Stmt
-	fortuneSelectStmt *sql.Stmt
-
-	worldRowCount = 10000
-)
+var worldRowCount = 10000
 
 type (
 	// Message is used for JSON reply.
@@ -39,55 +30,52 @@ type (
 
 	// Fortunes slice
 	Fortunes []*Fortune
-
-	// For sorting
-	byMessage struct{ Fortunes }
 )
 
-//‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
-// Global methods
-//___________________________________
+//‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
+// MySQL DB based implementation
+//___________________________________________________________________________
 
-// FetchRandomWorld method returns one world record info.
-func FetchRandomWorld(w *World) error {
-	err := worldSelectStmt.QueryRow(randomWorldNum()).Scan(&w.ID, &w.RandomNumber)
+// MySQLFetchRandomWorld method returns one world record info.
+func MySQLFetchRandomWorld(w *World) error {
+	err := db.MSworldSelectStmt.QueryRow(randomWorldNum()).Scan(&w.ID, &w.RandomNumber)
 	return err
 }
 
-// GetRandomWorlds method returns world record from db randomly.
-func GetRandomWorlds(count int) (*[]World, error) {
+// MySQLRandomWorlds method returns world record from db randomly.
+func MySQLRandomWorlds(count int) (*[]World, error) {
 	worlds := make([]World, count)
 	var err error
 	for i := 0; i < count; i++ {
 		w := &worlds[i]
-		if err = FetchRandomWorld(w); err != nil {
+		if err = MySQLFetchRandomWorld(w); err != nil {
 			return nil, err
 		}
 	}
 	return &worlds, nil
 }
 
-// UpdateRandomWorlds method updates random world records.
-func UpdateRandomWorlds(count int) (*[]World, error) {
+// MySQLUpdateRandomWorlds method updates random world records.
+func MySQLUpdateRandomWorlds(count int) (*[]World, error) {
 	worlds := make([]World, count)
 	var err error
 	for i := 0; i < count; i++ {
 		w := &worlds[i]
-		if err = FetchRandomWorld(w); err != nil {
+		if err = MySQLFetchRandomWorld(w); err != nil {
 			return nil, err
 		}
 
 		w.RandomNumber = uint16(randomWorldNum())
-		if _, err = worldUpdateStmt.Exec(w.RandomNumber, w.ID); err != nil {
+		if _, err = db.MSworldUpdateStmt.Exec(w.RandomNumber, w.ID); err != nil {
 			return nil, err
 		}
 	}
 	return &worlds, nil
 }
 
-// GetFortunes method returns fortunes records
-func GetFortunes() (Fortunes, error) {
-	rows, err := fortuneSelectStmt.Query()
+// MySQLFortunes method returns fortunes records
+func MySQLFortunes() (Fortunes, error) {
+	rows, err := db.MSfortuneSelectStmt.Query()
 	if err != nil {
 		return nil, err
 	}
@@ -103,38 +91,98 @@ func GetFortunes() (Fortunes, error) {
 	_ = rows.Close()
 
 	fortunes = append(fortunes, &Fortune{Message: "Additional fortune added at request time."})
-	sort.Sort(byMessage{fortunes})
+	sortFortunesByMessage(fortunes)
 	return fortunes, nil
 }
 
-//‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
-// Unexported methods
-//___________________________________
+//‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
+// PostgreSQL DB based implementation
+//___________________________________________________________________________
 
-func randomWorldNum() int {
-	return rand.Intn(worldRowCount) + 1
+// PGFetchRandomWorld method returns one world record info.
+func PGFetchRandomWorld(w *World) error {
+	return db.PostgreSQL.QueryRow("worldSelectStmt", randomWorldNum()).Scan(&w.ID, &w.RandomNumber)
 }
 
-func prepareStatements(e *aah.Event) {
+// PGRandomWorlds method returns world record from db randomly.
+func PGRandomWorlds(count int) (*[]World, error) {
+	worlds := make([]World, count)
 	var err error
-	if worldSelectStmt, err = db.DB().Prepare("SELECT id, randomNumber FROM World WHERE id = ?"); err != nil {
-		log.Fatal(err)
+	for i := 0; i < count; i++ {
+		w := &worlds[i]
+		if err = PGFetchRandomWorld(w); err != nil {
+			return nil, err
+		}
 	}
+	return &worlds, nil
+}
 
-	if worldUpdateStmt, err = db.DB().Prepare("UPDATE World SET randomNumber = ? WHERE id = ?"); err != nil {
-		log.Fatal(err)
+// PGUpdateRandomWorlds method updates random world records.
+func PGUpdateRandomWorlds(count int) (*[]World, error) {
+	worlds := make([]World, count)
+	var err error
+	for i := 0; i < count; i++ {
+		w := &worlds[i]
+		if err = PGFetchRandomWorld(w); err != nil {
+			return nil, err
+		}
+		w.RandomNumber = uint16(randomWorldNum())
 	}
 
-	if fortuneSelectStmt, err = db.DB().Prepare("SELECT id, message FROM Fortune"); err != nil {
-		log.Fatal(err)
+	// sorting is required for insert deadlock prevention.
+	sortWorldsByID(worlds)
+
+	txn, err := db.PostgreSQL.Begin()
+	if err != nil {
+		return nil, fmt.Errorf("Error starting transaction: %s", err)
+	}
+	for i := 0; i < count; i++ {
+		w := &worlds[i]
+		if _, err = txn.Exec("worldUpdateStmt", w.RandomNumber, w.ID); err != nil {
+			return nil, fmt.Errorf("Error updating world row %d: %s", i, err)
+		}
 	}
+	if err = txn.Commit(); err != nil {
+		return nil, fmt.Errorf("Error when commiting world rows: %s", err)
+	}
+
+	return &worlds, nil
 }
 
-// Sorting interfaces
-func (s Fortunes) Len() int            { return len(s) }
-func (s Fortunes) Swap(i, j int)       { s[i], s[j] = s[j], s[i] }
-func (s byMessage) Less(i, j int) bool { return s.Fortunes[i].Message < s.Fortunes[j].Message }
+// PGFortunes method returns fortunes records
+func PGFortunes() (Fortunes, error) {
+	rows, err := db.PostgreSQL.Query("fortuneSelectStmt")
+	if err != nil {
+		return nil, err
+	}
+
+	fortunes := make(Fortunes, 0, 16)
+	for rows.Next() {
+		var fortune Fortune
+		if err = rows.Scan(&fortune.ID, &fortune.Message); err != nil {
+			return nil, err
+		}
+		fortunes = append(fortunes, &fortune)
+	}
+	rows.Close()
+
+	fortunes = append(fortunes, &Fortune{Message: "Additional fortune added at request time."})
+	sortFortunesByMessage(fortunes)
+	return fortunes, nil
+}
+
+//‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
+// Unexported methods
+//___________________________________________________________________________
+
+func randomWorldNum() int {
+	return rand.Intn(worldRowCount) + 1
+}
+
+func sortFortunesByMessage(fortunes Fortunes) {
+	sort.Slice(fortunes, func(i, j int) bool { return fortunes[i].Message < fortunes[j].Message })
+}
 
-func init() {
-	aah.OnStart(prepareStatements, 2)
+func sortWorldsByID(worlds []World) {
+	sort.Slice(worlds, func(i, j int) bool { return worlds[i].ID < worlds[j].ID })
 }

+ 14 - 293
frameworks/Go/aah/src/benchmark/config/aah.conf

@@ -1,329 +1,50 @@
-###################################################
-# benchmark - aah framework application
+# -----------------------------------------------------------------------------
+# benchmark - aah Application Configuration
 #
-# Complete configuration reference:
-#   https://docs.aahframework.org/app-config.html
-###################################################
+# Refer documentation to explore and customize the configurations.
+# Doc: https://docs.aahframework.org/app-config.html
+# -----------------------------------------------------------------------------
 
-# Application name (non-whitespace)
-# Default value is `basename` of import path.
 name = "benchmark"
-
-# Friendly description of application
 desc = "aah framework web application"
+type = "web"
 
-# Configure file path of application PID file to be written.
-# Ensure application has appropriate permission and directory exists.
-# Default value is `<app-base-dir>/<app-binary-name>.pid`
-#pid_file = "/path/to/pidfile.pid"
-
-# -----------------------------------------------------------------
-# Server configuration - HTTP
-# Doc: https://docs.aahframework.org/app-config.html#section-server
-# -----------------------------------------------------------------
 server {
-  # For unix socket: unix:/tmp/aahframework.sock
-  # Default value is `empty` string.
-  #address = ""
-
-  # For port `80` and `443`, put empty string or a value
-  # Default value is 8080.
-  #port = ""
-
-  # Header value written as `Server` HTTP header.
-  # If you do not want to include `Server` header, comment it out.
-  header = "aah-go-server"
-
-  # Valid time units are "s = seconds", "m = minutes"
-  timeout {
-    # mapped to `http.Server.ReadTimeout`.
-    # Default value is `90s`.
-    #read = "90s"
-
-    # mapped to `http.Server.WriteTimeout`
-    # Default value is `90s`.
-    #write = "90s"
-
-    # aah sever graceful shutdown timeout
-    # Note: applicable only to go1.8 and above
-    # Default value is `60s`.
-    #grace_shutdown = "60s"
-  }
-
-  # Mapped to `http.Server.MaxHeaderBytes`.
-  # Default value is `1mb`.
-  #max_header_bytes = "1mb"
-
-  # HTTP server keep alive option.
-  # Default value is `true`.
-  #keep_alive = true
-
-  ssl {
-    # Default value is `false`.
-    #enable = false
-
-    # Default value is `empty` string.
-    #cert = ""
-
-    # Default value is `empty` string.
-    #key = ""
-
-    # Disabling HTTP/2 set it true.
-    # Default value is `false`.
-    #disable_http2 = true
-
-    lets_encrypt {
-      # To get SSL certificate from Let's Encrypt CA, enable it.
-      # Don't forget to enable `server.ssl.enable=true`.
-      # Default value is `false`.
-      #enable = false
-
-      # Host policy controls which domains the autocert will attempt
-      # to retrieve new certificates for. It does not affect cached certs.
-      # It is required, no default value.
-      #host_policy = ["example.org", "docs.example.org"]
-
-      # Renew before optionally specifies how early certificates should
-      # be renewed before they expire.
-      # Default value is `10` days.
-      #renew_before = 10
-
-      # Email optionally specifies a contact email address. This is used by CAs,
-      # such as Let's Encrypt, to notify about problems with issued certificates.
-      # If the Client's account key is already registered, Email is not used.
-      #email = "[email protected]"
-
-      # Force RSA makes the autocert generate certificates with 2048-bit RSA keys.
-      # If false, a default is used. Currently the default is
-      # EC-based keys using the P-256 curve.
-      #force_rsa = false
-
-      # Cache optionally stores and retrieves previously-obtained certificates
-      # autocert manager. By default certs will only be cached for the lifetime
-      # of the autocert manager.
-      #
-      # autocert manager passes the Cache certificates data encoded in PEM,
-      # with private/public parts combined in a single Cache.Put call,
-      # private key first.
-      # Default value is `empty` string
-      #cache_dir = "/Users/jeeva/autocert"
-    }
-  }
-
-  # To manage aah server effectively it is necessary to know details about the
-  # request, response, processing time, client IP address, etc. aah framework
-  # provides the flexible and configurable access log capabilities.
-  access_log {
-    # Enabling server access log
-    # Default value is `false`.
-    #enable = true
-
-    # Absolute path to access log file or relative path.
-    # Default location is application logs directory
-    #file = "{{ .AppName }}-access.log"
-
-    # Default server access log pattern
-    #pattern = "%clientip %custom:- %reqtime %reqmethod %requrl %reqproto %resstatus %ressize %restime %reqhdr:referer"
-
-    # Access Log channel buffer size
-    # Default value is `500`.
-    #channel_buffer_size = 500
-
-    # Include static files access log too.
-    # Default value is `true`.
-    #static_file = false
-  }
+  header = "aah"
 }
 
-# ------------------------------------------------------------------
-# Request configuration
-# Doc: https://docs.aahframework.org/app-config.html#section-request
-# ------------------------------------------------------------------
 request {
-
-  # aah framework encourages to have unique `Request Id` for each incoming
-  # request, it helps in traceability. If request has already `X-Request-Id`
-  # HTTP header then it does not generate one.
   id {
-    # Default value is `true`.
     enable = false
-
-    # Default value is `X-Request-Id`, change it if you have different one.
-    #header = "X-Request-Id"
-  }
-
-  # Default value is `32mb`, choose your value based on your use case
-  #multipart_size = "32mb"
-}
-
-# ---------------------------------------------------------------
-# i18n configuration
-# Doc: https://docs.aahframework.org/app-config.html#section-i18n
-# ---------------------------------------------------------------
-i18n {
-  # It is used as fallback if framework is unable to determine the
-  # locale from HTTP Request.
-  # Default value is `en`.
-  #default = "en"
-}
-
-# -----------------------------------------------------------------
-# Format configuration
-# Doc: https://docs.aahframework.org/app-config.html#section-format
-# -----------------------------------------------------------------
-format {
-  # Time format for auto parse and bind. aah tries to parse the
-  # time value in the order they defined till it gets success
-  # otherwise returns the error.
-  time = [
-    "2006-01-02T15:04:05Z07:00",
-    "2006-01-02T15:04:05Z",
-    "2006-01-02 15:04:05",
-    "2006-01-02"
-  ]
-}
-
-# ------------------------------------------------------------------
-# Runtime configuration
-# Doc: https://docs.aahframework.org/app-config.html#section-runtime
-# ------------------------------------------------------------------
-runtime {
-  debug {
-    # Choose an appropriate buffer size for collecting all goroutines stack trace
-    # dump based on your case.
-    # Default value is `2mb`.
-    #stack_buffer_size = "2mb"
-
-    # Whether to collect all the Go routines details or not.
-    # Default value is `false`.
-    #all_goroutines = true
   }
 }
 
-# -----------------------------------------------------------------
-# Render configuration
-# Doc: https://docs.aahframework.org/app-config.html#section-render
-# -----------------------------------------------------------------
 render {
-  # aah framework chooses the `Content-Type` value automatically based on
-  # configuration if `aah.Reply()` builder value is not set. It selects in
-  # the order of:
-  #  - Based on URL file extension, supported `.html`, `.htm`, `.json`, `.js`, `.xml` and `.txt`
-  #  - Request Accept Header - Most Qualified one as per RFC7321
-  #  - Based `render.default` value supported types are `html`, `json`, `xml` and `text`
-  #  - Finally aah framework uses `http.DetectContentType` API
-  # Default value is `empty` string.
   default = "html"
-
-  # Pretty print option is helpful in `dev` environment profile.
-  # It is only applicable to JSON and XML.
-  # Default value is `false`.
-  #pretty = true
-
-  # Gzip compression configuration for HTTP response.
   gzip {
-    # By default Gzip compression is enabled in aah framework, however
-    # framework ensures HTTP client accepts Gzip response otherwise
-    # it won't use Gzip compression.
-    #
-    # Tips: If you have nginx or apache web server enabled with gzip in-front
-    # of aah server the set this value to `false`.
-    #
-    # Default value is `true`.
     enable = false
-
-    # Used to control Gzip compression levels. Valid levels are
-    # 1 = BestSpeed to 9 = BestCompression.
-    # Default value is `4`.
-    #level = 4
   }
 }
 
-# ------------------------------------------------------------------
-# Cache configuration
-# Doc: https://docs.aahframework.org/static-files.html#cache-control
-# ------------------------------------------------------------------
 cache {
   static {
-    # Default `Cache-Control` for all static files,
-    # if specific mime type is not defined.
     default_cache_control = "public, max-age=31536000"
-
-    # Define by mime types, if mime is not present then default is applied.
-    # Config is very flexible to define by mime type.
-    #
-    # Create a unique name and provide `mime` with comma separated value
-    # and `cache_control`.
-    # mime_types {
-    #   css_js {
-    #     mime = "text/css, application/javascript"
-    #     cache_control = "public, max-age=604800, proxy-revalidate"
-    #   }
-    #
-    #   images {
-    #     mime = "image/jpeg, image/png, image/gif, image/svg+xml, image/x-icon"
-    #     cache_control = "public, max-age=2628000, proxy-revalidate"
-    #   }
-    # }
   }
 }
 
-# ---------------------------------------------------------------
-# View configuration
-# Doc: https://docs.aahframework.org/app-config.html#section-view
-# ---------------------------------------------------------------
 view {
-  # Choosing view engine for application. In the upcoming release framework
-  # will provide support to amber, pongo2, and jade. However you can implement
-  # on your own with simple `view.Enginer` interface.
-  # Default value is `go`. Currently only `go` is supported.
-  #engine = "go"
-
-  # Choose your own view file extension.
-  # Default value is `.html`.
-  #ext = ".html"
-
-  # Choose whether you need a case sensitive view file resolve or not.
-  # For e.g.: "/views/pages/app/login.tmpl" == "/views/pages/App/Login.tmpl"
-  # Default value is `false`.
-  #case_sensitive = false
-
-  # To use custom Go template delimiters for view files.
-  # Default value is `{{.}}`.
-  #delimiters = "{{.}}"
-
-  # Framework chooses the default app layout as `master.html` if you do not
-  # provide one. However you may have pages or template without layout too.
-  # So option to disable the default layout for HTML.
-  # Default value is `true`. Available since v0.6
-  #default_layout = false
-}
-
-# DataSource config
-datasource {
-  benchmark {
-    driver = "mysql"
-    url = "benchmarkdbuser:benchmarkdbpass@tcp(%s:3306)/hello_world"
-  }
+  engine = "go"
+  ext = ".html"
+  delimiters = "{{.}}"
 }
 
-# --------------------------------------------------------------
-# Application Security
-# Doc: https://docs.aahframework.org/security-config.html
-# --------------------------------------------------------------
 include "./security.conf"
 
-# --------------------------------------------------------------
-# Environment Profiles e.g.: dev, qa, prod
-# Doc: https://docs.aahframework.org/app-config.html#section-env
-# --------------------------------------------------------------
 env {
-  # Indicates active profile name for application configuration.
-  # Default value is `dev`.
-  #active = "dev"
+  active = "bm_default"
 
-  # ----------------------------------
-  # Environment profile configurations
-  # ----------------------------------
+  # -------------------------------------------------
+  # Including Environment profile configurations
+  # -------------------------------------------------
   include "./env/*.conf"
 }

+ 12 - 0
frameworks/Go/aah/src/benchmark/config/env/bm-default.conf

@@ -0,0 +1,12 @@
+# ---------------------------------
+# Default Benchmark profile
+# ---------------------------------
+
+bm_default {
+    
+    log {
+        receiver = "console"
+        level = "error"
+    }
+
+}

+ 21 - 0
frameworks/Go/aah/src/benchmark/config/env/bm-mysql.conf

@@ -0,0 +1,21 @@
+# ---------------------------------
+# MySQL Benchmark profile
+# ---------------------------------
+
+bm_mysql {
+    
+    log {
+        receiver = "console"
+        level = "error"
+    }
+
+    datasource {
+        benchmark {
+            mysql {
+                driver = "mysql"
+                url = "benchmarkdbuser:benchmarkdbpass@tcp(tfb-database:3306)/hello_world"
+            }
+        }
+    }
+
+}

+ 24 - 0
frameworks/Go/aah/src/benchmark/config/env/bm-postgresql.conf

@@ -0,0 +1,24 @@
+# ---------------------------------
+# PostgreSQL Benchmark profile
+# ---------------------------------
+
+bm_postgresql {
+    
+    log {
+        receiver = "console"
+        level = "error"
+    }
+
+    datasource {
+        benchmark {
+            postgresql {
+                host = "tfb-database"
+                port = 5432
+                dbname = "hello_world"
+                user = "benchmarkdbuser"
+                password = "benchmarkdbpass"
+            }
+        }
+    }
+
+}

+ 0 - 24
frameworks/Go/aah/src/benchmark/config/env/dev.conf

@@ -1,24 +0,0 @@
-# ---------------------------------
-# Development Configuration Section
-# ---------------------------------
-
-dev {
-
-  # --------------------------------------------------
-  # Log Configuration
-  # Doc: https://docs.aahframework.org/log-config.html
-  # --------------------------------------------------
-  log {
-    receiver = "console"
-    level = "info"
-  }
-
-  # -------------------------
-  # Render configuration
-  # -------------------------
-  render {
-    # pretty is only applicable to JSON & XML rendering
-    pretty = true
-  }
-
-}

+ 0 - 61
frameworks/Go/aah/src/benchmark/config/env/prod.conf

@@ -1,61 +0,0 @@
-# ---------------------------------
-# Production Configuration Section
-# ---------------------------------
-
-prod {
-
-  # ---------------------------
-  # Production Hostname mapping
-  # ---------------------------
-  routes {
-    domains {
-      localhost {
-        host = "TFB-server"
-      }
-    }
-  }
-
-  # --------------------------------------------------
-  # Log Configuration
-  # Doc: https://docs.aahframework.org/log-config.html
-  # --------------------------------------------------
-  log {
-    # Receiver is where is log values gets logged. Currently framework
-    # supports `console` and `file` as a receivers.
-    # Default value is `console`.
-    #receiver = "file"
-
-    # Level indicates the logging levels like `ERROR`, `WARN`, `INFO`, `DEBUG`
-    # and `TRACE`. Config value can be in lowercase or uppercase.
-    # Default value is `debug`.
-    level = "error"
-
-    # Pattern config defines the message flags and formatting while logging
-    # into receivers. Customize it as per your need, learn more about flags
-    # and format - https://docs.aahframework.org/log-config.html#pattern
-    # Default value is `%time:2006-01-02 15:04:05.000 %level:-5 %message`
-    #pattern = "%time:2006-01-02 15:04:05.000 %level:-5 %message"
-
-    # File config attribute is applicable only to `file` receiver type.
-    # Default value is `aah-log-file.log`.
-    #file = "benchmark.log"
-
-    # Rotate config section is applicable only to `file` receiver type.
-    # Default rotation is 'daily'.
-    rotate {
-      # Mode is used to determine rotate mode. Currently it supports `daily`,
-      # `lines` and `size`.
-      # Default value is `daily`.
-      #mode = "daily"
-
-      # This is applicable only to if `mode` is `size`.
-      # Default value is 100MB.
-      #size = 500
-
-      # This is applicable only to if `mode` is `lines`.
-      # Default value is unlimited.
-      #lines = 100000
-    }
-  }
-
-}

+ 44 - 39
frameworks/Go/aah/src/benchmark/config/routes.conf

@@ -1,31 +1,16 @@
-####################################################
+# -----------------------------------------------------------------------------
 # benchmark - Application Routes Configuration
 #
-# Complete routes configuration reference:
-#   https://docs.aahframework.org/routes-config.html
-####################################################
+# Refer documentation to explore and configure routes.
+# Doc: https://docs.aahframework.org/routing.html
+# -----------------------------------------------------------------------------
 
-#------------------------------------------------------------------------
-# Domain and sub-domain configuration goes into section `domains { ... }`
-#------------------------------------------------------------------------
 domains {
 
-  # Pick your choice of an `unique keyname` to define your domain section
-  # in the routes configuration.
-  # For e.g.: Domain name/ip address with port no
   localhost {
     name = "benchmark routes"
-
-    # aah supports multi-domain routes configuration out-of-the-box.
-    # `host` used to determine domain routes for the incoming request.
-    # For e.g: example.org
     host = "localhost"
 
-    #-----------------------------------------------------------------------------
-    # Application routes
-    # Doc: https://docs.aahframework.org/routes-config.html#section-routes
-    # Doc: https://docs.aahframework.org/routes-config.html#namespace-group-routes
-    #-----------------------------------------------------------------------------
     routes {
 
       json {
@@ -34,35 +19,55 @@ domains {
         action = "JSON"
       }
 
-      db {
-        path = "/db"
+      plaintext {
+        path = "/plaintext"
         controller = "AppController"
-        action = "GetWorld"
+        action = "Plaintext"
       }
 
-      dbs {
-        path = "/queries"
+      # For MySQL datasource
+      db {
+        path = "/db"
         controller = "AppController"
-        action = "GetWorlds"
-      }
+        action = "World"
 
-      fortunes {
-        path = "/fortunes"
-        controller = "AppController"
-        action = "Fortunes"
+        routes {
+          dbs {
+            path = "/queries"
+            action = "Worlds"
+          }
+          fortunes {
+            path = "/fortunes"
+            action = "Fortunes"
+          }
+          updates {
+            path = "/updates"
+            action = "UpdateWorlds"
+          }
+        }
       }
 
-      updates {
-        path = "/updates"
+      # For PostgreSQL datasource
+      pg_db {
+        path = "/pg-db"
         controller = "AppController"
-        action = "UpdateWorlds"
-      }
+        action = "PGWorld"
 
-      plaintext {
-        path = "/plaintext"
-        controller = "AppController"
-        action = "Plaintext"
-      }
+        routes {
+          pg_dbs {
+            path = "/queries"
+            action = "PGWorlds"
+          }
+          pg_fortunes {
+            path = "/fortunes"
+            action = "PGFortunes"
+          }
+          pg_updates {
+            path = "/updates"
+            action = "PGUpdateWorlds"
+          }
+        }
+      }      
 
     } # end - routes
 

+ 5 - 21
frameworks/Go/aah/src/benchmark/config/security.conf

@@ -1,28 +1,12 @@
-######################################################
+# -----------------------------------------------------------------------------
 # benchmark - Application Security Configuration
 #
-# Complete routes configuration reference:
-#   https://docs.aahframework.org/security-config.html
-######################################################
+# Refer documentation to explore and customize the configurations.
+# Doc: https://docs.aahframework.org/security-config.html
+# -----------------------------------------------------------------------------
 
 security {
-  # -----------------------------------------------------------------------
-  # Session configuration
-  # HTTP state management across multiple requests.
-  # Doc: https://docs.aahframework.org/security-config.html#section-session
-  # -----------------------------------------------------------------------
-  session {
-
-  }
-
-  # ---------------------------------------------------------------------------
-  # HTTP Secure Header(s)
-  # Application security headers with many safe defaults.
-  # Doc: https://docs.aahframework.org/security-config.html#section-http-header
-  #
-  # Tip: Quick way to verify secure headers - https://securityheaders.io
-  # ---------------------------------------------------------------------------
   http_header {
-
+    enable = false
   }
 }

+ 113 - 17
frameworks/Go/aah/src/benchmark/glide.lock

@@ -1,45 +1,141 @@
-hash: b59c0b33b5d6504b9f21d3f99163f8c8a21e4b450399cf7ea730920d982c1756
-updated: 2017-09-03T00:28:05.557966684Z
+hash: a61d685b506cb25836a56a85c6c67a2ecf0e827bbd2921e46068d24735e4618e
+updated: 2018-07-07T18:56:52.836749848-07:00
 imports:
 - name: aahframework.org/aah.v0
-  version: 12414997d4457838756dcb53e2e3b6a184d4950f
+  version: 3a30b0c90ca2ca9c2d0d31fabab47b6689ab688c
 - name: aahframework.org/ahttp.v0
-  version: f9b651b8092ec7477d4349bce07eb95c482306c8
+  version: d4d049fa4cb0bdfc40e936e4dfdea876e9a3b3d5
+- name: aahframework.org/ainsp.v0
+  version: 14b9cae19d5d96d73369dacbf82f03499b780984
 - name: aahframework.org/aruntime.v0
-  version: 3368d72836c245d93409bcf73e2eb5e74cf02767
+  version: 2086b0399afb84f1c086b25acb4d772c2e59a6af
 - name: aahframework.org/config.v0
-  version: 5e0e808cbd7cfa9a9b51c26adb2af891bd73ccda
+  version: 4a83eccfa602aa46ee50a19785e04376a2c9df0c
 - name: aahframework.org/essentials.v0
-  version: cf06313c993843e9affb565fde6177ccd1807921
+  version: c79d02cfeb97faee414c6353a8e8b76ac67e3d0d
 - name: aahframework.org/forge.v0
-  version: 9f3b186d1c58fb40060cc9783d990d3a9c5e0176
+  version: dd8ea2dd9508db8e0731255a104a904f4410fccb
   subpackages:
   - token
 - name: aahframework.org/i18n.v0
-  version: 8558a9d1e89af246eda371c0b0e66e83b12dbded
+  version: 82db044e58f6ee644e0c8f1db36cb1a423b3859d
 - name: aahframework.org/log.v0
-  version: a6c07023e1cb69de3f987f2bd90be33446b5ba0e
+  version: e8fbaf78e3c4c935debeee51a2e3765d0a4a49f1
 - name: aahframework.org/router.v0
-  version: 14ed79c8c87d3e368633b67ba37010f2d3d6c12a
+  version: 2e5e6f7789cdc68143f1e7603ce6fd98c8da5ac4
 - name: aahframework.org/security.v0
-  version: 308ebec6eab3744c83df77637c30adff959dc782
+  version: c82895034e1356832e421a07010ac9f10e1b6a18
   subpackages:
   - acrypto
+  - anticsrf
   - authc
   - authz
+  - cookie
   - scheme
   - session
 - name: aahframework.org/valpar.v0
-  version: b66ffe09843404678baecd85d7d0401ea7d9e8f3
+  version: d3756c4d443e126aba806cf3f2d33a5e5318f442
+- name: aahframework.org/vfs.v0
+  version: 9213e4eb58eb4e79901707969e9c42035022eb99
 - name: aahframework.org/view.v0
-  version: 38179594120f15376a4d8305ccc87645f5a88637
-- name: github.com/go-sql-driver/mysql
-  version: 26471af196a17ee75a22e6481b5a5897fb16b081
+  version: fa51a6bbdb8afd897d52a6c18f750c95786e8408
+- name: aahframework.org/ws.v0
+  version: b9882fce55c5913778c2b8fbd562b1bd50760ded
+- name: cloud.google.com/go
+  version: 3a236a566c90c7db8167247d8add7d8c753880bf
+  subpackages:
+  - compute/metadata
+- name: github.com/go-playground/locales
+  version: f63010822830b6fe52288ee52d5a1151088ce039
+  subpackages:
+  - currency
+- name: github.com/go-playground/universal-translator
+  version: 71201497bace774495daed26a3874fd339e0b538
+- name: github.com/gobwas/httphead
+  version: 2c6c146eadee0b69f856f87e3e9f1d0cd6aad2f5
+- name: github.com/gobwas/pool
+  version: fa3125c39d7eca32e1387bb69b1b38dcb31b1e0b
+  subpackages:
+  - internal/pmath
+  - pbufio
+  - pbytes
+- name: github.com/gobwas/ws
+  version: 2c0cb1ddcc090935502e98ef8f7d7198b23a67e3
+  subpackages:
+  - wsutil
+- name: github.com/golang/protobuf
+  version: 1325a051a2753cd67556b182843b1b693d0854cd
+  subpackages:
+  - proto
 - name: golang.org/x/crypto
-  version: 81e90905daefcd6fd217b62423c0908922eadb30
+  version: a49355c7e3f8fe157a85be2f77e6e269a0f89602
   subpackages:
   - acme
   - acme/autocert
   - bcrypt
   - blowfish
+  - pbkdf2
+  - scrypt
+- name: golang.org/x/net
+  version: 32a936f46389aa10549d60bd7833e54b01685d09
+  subpackages:
+  - context
+  - context/ctxhttp
+- name: golang.org/x/oauth2
+  version: ef147856a6ddbb60760db74283d2424e98c87bff
+  subpackages:
+  - amazon
+  - bitbucket
+  - cern
+  - clientcredentials
+  - facebook
+  - fitbit
+  - foursquare
+  - github
+  - gitlab
+  - google
+  - heroku
+  - hipchat
+  - internal
+  - jws
+  - jwt
+  - kakao
+  - linkedin
+  - mailchimp
+  - mailru
+  - mediamath
+  - microsoft
+  - odnoklassniki
+  - paypal
+  - slack
+  - spotify
+  - twitch
+  - uber
+  - vk
+  - yahoo
+  - yandex
+- name: golang.org/x/sys
+  version: 3c6ecd8f22c6f40fbeec94c000a069d7d87c7624
+  subpackages:
+  - unix
+- name: google.golang.org/appengine
+  version: b1f26356af11148e710935ed1ac8a7f5702c7612
+  subpackages:
+  - internal
+  - internal/app_identity
+  - internal/base
+  - internal/datastore
+  - internal/log
+  - internal/modules
+  - internal/remote_api
+  - internal/urlfetch
+  - urlfetch
+- name: gopkg.in/go-playground/validator.v9
+  version: ce9336f6e200cbb2e7c5672b36095b03f8bf5af7
+- name: github.com/go-sql-driver/mysql
+  version: 26471af196a17ee75a22e6481b5a5897fb16b081
+- name: github.com/jackc/pgx
+  version: 39bbc98d99d7b666759f84514859becf8067128f
+- name: github.com/pkg/errors
+  version: 816c9085562cd7ee03e7f8188a1cfd942858cded
 testImports: []

+ 2 - 1
frameworks/Go/aah/src/benchmark/glide.yaml

@@ -1,5 +1,6 @@
 package: benchmark
 import:
 - package: aahframework.org/aah.v0
-  version: ^v0.8
+  version: ^v0.11.0
 - package: github.com/go-sql-driver/mysql
+- package: github.com/jackc/pgx