hunk.code_window: package api
   import (
   	"strings"
   	"github.com/mattermost/platform/app"
   	"github.com/mattermost/platform/model"
   )
  
hunk.labels: keep keep keep keep add keep keep keep
hunk.after_edit: 	l4g "github.com/alecthomas/log4go"
  
hunk.file_path: api/command_msg.go
hunk.type: add
file: // +build go1.1
  
  package pq
  
  import (
  	"bufio"
  	"bytes"
  	"database/sql"
  	"database/sql/driver"
  	"io"
  	"math/rand"
  	"net"
  	"runtime"
  	"strconv"
  	"strings"
  	"sync"
  	"testing"
  	"time"
  
  	"github.com/lib/pq/oid"
  )
  
  var (
  	selectStringQuery = "SELECT '" + strings.Repeat("0123456789", 10) + "'"
  	selectSeriesQuery = "SELECT generate_series(1, 100)"
  )
  
  func BenchmarkSelectString(b *testing.B) {
  	var result string
  	benchQuery(b, selectStringQuery, &result)
  }
  
  func BenchmarkSelectSeries(b *testing.B) {
  	var result int
  	benchQuery(b, selectSeriesQuery, &result)
  }
  
  func benchQuery(b *testing.B, query string, result interface{}) {
  	b.StopTimer()
  	db := openTestConn(b)
  	defer db.Close()
  	b.StartTimer()
  
  	for i := 0; i < b.N; i++ {
  		benchQueryLoop(b, db, query, result)
  	}
  }
  
  func benchQueryLoop(b *testing.B, db *sql.DB, query string, result interface{}) {
  	rows, err := db.Query(query)
  	if err != nil {
  		b.Fatal(err)
  	}
  	defer rows.Close()
  	for rows.Next() {
  		err = rows.Scan(result)
  		if err != nil {
  			b.Fatal("failed to scan", err)
  		}
  	}
  }
  
  // reading from circularConn yields content[:prefixLen] once, followed by
  // content[prefixLen:] over and over again. It never returns EOF.
  type circularConn struct {
  	content   string
  	prefixLen int
  	pos       int
  	net.Conn  // for all other net.Conn methods that will never be called
  }
  
  func (r *circularConn) Read(b []byte) (n int, err error) {
  	n = copy(b, r.content[r.pos:])
  	r.pos += n
  	if r.pos >= len(r.content) {
  		r.pos = r.prefixLen
  	}
  	return
  }
  
  func (r *circularConn) Write(b []byte) (n int, err error) { return len(b), nil }
  
  func (r *circularConn) Close() error { return nil }
  
  func fakeConn(content string, prefixLen int) *conn {
  	c := &circularConn{content: content, prefixLen: prefixLen}
  	return &conn{buf: bufio.NewReader(c), c: c}
  }
  
  // This benchmark is meant to be the same as BenchmarkSelectString, but takes
  // out some of the factors this package can't control. The numbers are less noisy,
  // but also the costs of network communication aren't accurately represented.
  func BenchmarkMockSelectString(b *testing.B) {
  	b.StopTimer()
  	// taken from a recorded run of BenchmarkSelectString
  	// See: http://www.postgresql.org/docs/current/static/protocol-message-formats.html
  	const response = "1\x00\x00\x00\x04" +
  		"t\x00\x00\x00\x06\x00\x00" +
  		"T\x00\x00\x00!\x00\x01?column?\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\xc1\xff\xfe\xff\xff\xff\xff\x00\x00" +
  		"Z\x00\x00\x00\x05I" +
  		"2\x00\x00\x00\x04" +
  		"D\x00\x00\x00n\x00\x01\x00\x00\x00d0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789" +
  		"C\x00\x00\x00\rSELECT 1\x00" +
  		"Z\x00\x00\x00\x05I" +
  		"3\x00\x00\x00\x04" +
  		"Z\x00\x00\x00\x05I"
  	c := fakeConn(response, 0)
  	b.StartTimer()
  
  	for i := 0; i < b.N; i++ {
  		benchMockQuery(b, c, selectStringQuery)
  	}
  }
  
  var seriesRowData = func() string {
  	var buf bytes.Buffer
  	for i := 1; i <= 100; i++ {
  		digits := byte(2)
  		if i >= 100 {
  			digits = 3
  		} else if i < 10 {
  			digits = 1
  		}
  		buf.WriteString("D\x00\x00\x00")
  		buf.WriteByte(10 + digits)
  		buf.WriteString("\x00\x01\x00\x00\x00")
  		buf.WriteByte(digits)
  		buf.WriteString(strconv.Itoa(i))
  	}
  	return buf.String()
  }()
  
  func BenchmarkMockSelectSeries(b *testing.B) {
  	b.StopTimer()
  	var response = "1\x00\x00\x00\x04" +
  		"t\x00\x00\x00\x06\x00\x00" +
  		"T\x00\x00\x00!\x00\x01?column?\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\xc1\xff\xfe\xff\xff\xff\xff\x00\x00" +
  		"Z\x00\x00\x00\x05I" +
  		"2\x00\x00\x00\x04" +
  		seriesRowData +
  		"C\x00\x00\x00\x0fSELECT 100\x00" +
  		"Z\x00\x00\x00\x05I" +
  		"3\x00\x00\x00\x04" +
  		"Z\x00\x00\x00\x05I"
  	c := fakeConn(response, 0)
  	b.StartTimer()
  
  	for i := 0; i < b.N; i++ {
  		benchMockQuery(b, c, selectSeriesQuery)
  	}
  }
  
  func benchMockQuery(b *testing.B, c *conn, query string) {
  	stmt, err := c.Prepare(query)
  	if err != nil {
  		b.Fatal(err)
  	}
  	defer stmt.Close()
  	rows, err := stmt.Query(nil)
  	if err != nil {
  		b.Fatal(err)
  	}
  	defer rows.Close()
  	var dest [1]driver.Value
  	for {
  		if err := rows.Next(dest[:]); err != nil {
  			if err == io.EOF {
  				break
  			}
  			b.Fatal(err)
  		}
  	}
  }
  
  func BenchmarkPreparedSelectString(b *testing.B) {
  	var result string
  	benchPreparedQuery(b, selectStringQuery, &result)
  }
  
  func BenchmarkPreparedSelectSeries(b *testing.B) {
  	var result int
  	benchPreparedQuery(b, selectSeriesQuery, &result)
  }
  
  func benchPreparedQuery(b *testing.B, query string, result interface{}) {
  	b.StopTimer()
  	db := openTestConn(b)
  	defer db.Close()
  	stmt, err := db.Prepare(query)
  	if err != nil {
  		b.Fatal(err)
  	}
  	defer stmt.Close()
  	b.StartTimer()
  
  	for i := 0; i < b.N; i++ {
  		benchPreparedQueryLoop(b, db, stmt, result)
  	}
  }
  
  func benchPreparedQueryLoop(b *testing.B, db *sql.DB, stmt *sql.Stmt, result interface{}) {
  	rows, err := stmt.Query()
  	if err != nil {
  		b.Fatal(err)
  	}
  	if !rows.Next() {
  		rows.Close()
  		b.Fatal("no rows")
  	}
  	defer rows.Close()
  	for rows.Next() {
  		err = rows.Scan(&result)
  		if err != nil {
  			b.Fatal("failed to scan")
  		}
  	}
  }
  
  // See the comment for BenchmarkMockSelectString.
  func BenchmarkMockPreparedSelectString(b *testing.B) {
  	b.StopTimer()
  	const parseResponse = "1\x00\x00\x00\x04" +
  		"t\x00\x00\x00\x06\x00\x00" +
  		"T\x00\x00\x00!\x00\x01?column?\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\xc1\xff\xfe\xff\xff\xff\xff\x00\x00" +
  		"Z\x00\x00\x00\x05I"
  	const responses = parseResponse +
  		"2\x00\x00\x00\x04" +
  		"D\x00\x00\x00n\x00\x01\x00\x00\x00d0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789" +
  		"C\x00\x00\x00\rSELECT 1\x00" +
  		"Z\x00\x00\x00\x05I"
  	c := fakeConn(responses, len(parseResponse))
  
  	stmt, err := c.Prepare(selectStringQuery)
  	if err != nil {
  		b.Fatal(err)
  	}
  	b.StartTimer()
  
  	for i := 0; i < b.N; i++ {
  		benchPreparedMockQuery(b, c, stmt)
  	}
  }
  
  func BenchmarkMockPreparedSelectSeries(b *testing.B) {
  	b.StopTimer()
  	const parseResponse = "1\x00\x00\x00\x04" +
  		"t\x00\x00\x00\x06\x00\x00" +
  		"T\x00\x00\x00!\x00\x01?column?\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\xc1\xff\xfe\xff\xff\xff\xff\x00\x00" +
  		"Z\x00\x00\x00\x05I"
  	var responses = parseResponse +
  		"2\x00\x00\x00\x04" +
  		seriesRowData +
  		"C\x00\x00\x00\x0fSELECT 100\x00" +
  		"Z\x00\x00\x00\x05I"
  	c := fakeConn(responses, len(parseResponse))
  
  	stmt, err := c.Prepare(selectSeriesQuery)
  	if err != nil {
  		b.Fatal(err)
  	}
  	b.StartTimer()
  
  	for i := 0; i < b.N; i++ {
  		benchPreparedMockQuery(b, c, stmt)
  	}
  }
  
  func benchPreparedMockQuery(b *testing.B, c *conn, stmt driver.Stmt) {
  	rows, err := stmt.Query(nil)
  	if err != nil {
  		b.Fatal(err)
  	}
  	defer rows.Close()
  	var dest [1]driver.Value
  	for {
  		if err := rows.Next(dest[:]); err != nil {
  			if err == io.EOF {
  				break
  			}
  			b.Fatal(err)
  		}
  	}
  }
  
  func BenchmarkEncodeInt64(b *testing.B) {
  	for i := 0; i < b.N; i++ {
  		encode(&parameterStatus{}, int64(1234), oid.T_int8)
  	}
  }
  
  func BenchmarkEncodeFloat64(b *testing.B) {
  	for i := 0; i < b.N; i++ {
  		encode(&parameterStatus{}, 3.14159, oid.T_float8)
  	}
  }
  
  var testByteString = []byte("abcdefghijklmnopqrstuvwxyz")
  
  func BenchmarkEncodeByteaHex(b *testing.B) {
  	for i := 0; i < b.N; i++ {
  		encode(&parameterStatus{serverVersion: 90000}, testByteString, oid.T_bytea)
  	}
  }
  func BenchmarkEncodeByteaEscape(b *testing.B) {
  	for i := 0; i < b.N; i++ {
  		encode(&parameterStatus{serverVersion: 84000}, testByteString, oid.T_bytea)
  	}
  }
  
  func BenchmarkEncodeBool(b *testing.B) {
  	for i := 0; i < b.N; i++ {
  		encode(&parameterStatus{}, true, oid.T_bool)
  	}
  }
  
  var testTimestamptz = time.Date(2001, time.January, 1, 0, 0, 0, 0, time.Local)
  
  func BenchmarkEncodeTimestamptz(b *testing.B) {
  	for i := 0; i < b.N; i++ {
  		encode(&parameterStatus{}, testTimestamptz, oid.T_timestamptz)
  	}
  }
  
  var testIntBytes = []byte("1234")
  
  func BenchmarkDecodeInt64(b *testing.B) {
  	for i := 0; i < b.N; i++ {
  		decode(&parameterStatus{}, testIntBytes, oid.T_int8, formatText)
  	}
  }
  
  var testFloatBytes = []byte("3.14159")
  
  func BenchmarkDecodeFloat64(b *testing.B) {
  	for i := 0; i < b.N; i++ {
  		decode(&parameterStatus{}, testFloatBytes, oid.T_float8, formatText)
  	}
  }
  
  var testBoolBytes = []byte{'t'}
  
  func BenchmarkDecodeBool(b *testing.B) {
  	for i := 0; i < b.N; i++ {
  		decode(&parameterStatus{}, testBoolBytes, oid.T_bool, formatText)
  	}
  }
  
  func TestDecodeBool(t *testing.T) {
  	db := openTestConn(t)
  	rows, err := db.Query("select true")
  	if err != nil {
  		t.Fatal(err)
  	}
  	rows.Close()
  }
  
  var testTimestamptzBytes = []byte("2013-09-17 22:15:32.360754-07")
  
  func BenchmarkDecodeTimestamptz(b *testing.B) {
  	for i := 0; i < b.N; i++ {
  		decode(&parameterStatus{}, testTimestamptzBytes, oid.T_timestamptz, formatText)
  	}
  }
  
  func BenchmarkDecodeTimestamptzMultiThread(b *testing.B) {
  	oldProcs := runtime.GOMAXPROCS(0)
  	defer runtime.GOMAXPROCS(oldProcs)
  	runtime.GOMAXPROCS(runtime.NumCPU())
  	globalLocationCache = newLocationCache()
  
  	f := func(wg *sync.WaitGroup, loops int) {
  		defer wg.Done()
  		for i := 0; i < loops; i++ {
  			decode(&parameterStatus{}, testTimestamptzBytes, oid.T_timestamptz, formatText)
  		}
  	}
  
  	wg := &sync.WaitGroup{}
  	b.ResetTimer()
  	for j := 0; j < 10; j++ {
  		wg.Add(1)
  		go f(wg, b.N/10)
  	}
  	wg.Wait()
  }
  
  func BenchmarkLocationCache(b *testing.B) {
  	globalLocationCache = newLocationCache()
  	for i := 0; i < b.N; i++ {
  		globalLocationCache.getLocation(rand.Intn(10000))
  	}
  }
  
  func BenchmarkLocationCacheMultiThread(b *testing.B) {
  	oldProcs := runtime.GOMAXPROCS(0)
  	defer runtime.GOMAXPROCS(oldProcs)
  	runtime.GOMAXPROCS(runtime.NumCPU())
  	globalLocationCache = newLocationCache()
  
  	f := func(wg *sync.WaitGroup, loops int) {
  		defer wg.Done()
  		for i := 0; i < loops; i++ {
  			globalLocationCache.getLocation(rand.Intn(10000))
  		}
  	}
  
  	wg := &sync.WaitGroup{}
  	b.ResetTimer()
  	for j := 0; j < 10; j++ {
  		wg.Add(1)
  		go f(wg, b.N/10)
  	}
  	wg.Wait()
  }
  
  // Stress test the performance of parsing results from the wire.
  func BenchmarkResultParsing(b *testing.B) {
  	b.StopTimer()
  
  	db := openTestConn(b)
  	defer db.Close()
  	_, err := db.Exec("BEGIN")
  	if err != nil {
  		b.Fatal(err)
  	}
  
  	b.StartTimer()
  	for i := 0; i < b.N; i++ {
  		res, err := db.Query("SELECT generate_series(1, 50000)")
  		if err != nil {
  			b.Fatal(err)
  		}
  		res.Close()
  	}
  }
  