mirror of
https://github.com/Oxalide/vsphere-influxdb-go.git
synced 2023-10-10 11:36:51 +00:00
add vendoring with go dep
This commit is contained in:
58
vendor/github.com/influxdata/influxdb/stress/v2/stress_client/commune.go
generated
vendored
Normal file
58
vendor/github.com/influxdata/influxdb/stress/v2/stress_client/commune.go
generated
vendored
Normal file
@@ -0,0 +1,58 @@
|
||||
package stressClient
|
||||
|
||||
import (
|
||||
"log"
|
||||
"time"
|
||||
|
||||
"github.com/influxdata/influxdb/models"
|
||||
)
|
||||
|
||||
// Communes are a method for passing points between InsertStatements and QueryStatements.
|
||||
|
||||
type commune struct {
|
||||
ch chan string
|
||||
storedPoint models.Point
|
||||
}
|
||||
|
||||
// NewCommune creates a new commune with a buffered chan of length n
|
||||
func newCommune(n int) *commune {
|
||||
return &commune{ch: make(chan string, n)}
|
||||
}
|
||||
|
||||
func (c *commune) point(precision string) models.Point {
|
||||
|
||||
pt := []byte(<-c.ch)
|
||||
|
||||
p, err := models.ParsePointsWithPrecision(pt, time.Now().UTC(), precision)
|
||||
|
||||
if err != nil {
|
||||
log.Fatalf("Error parsing point for commune\n point: %v\n error: %v\n", pt, err)
|
||||
}
|
||||
|
||||
if len(p) == 0 {
|
||||
return c.storedPoint
|
||||
}
|
||||
|
||||
c.storedPoint = p[0]
|
||||
return p[0]
|
||||
}
|
||||
|
||||
// SetCommune creates a new commune on the StressTest
|
||||
func (st *StressTest) SetCommune(name string) chan<- string {
|
||||
com := newCommune(10)
|
||||
st.communes[name] = com
|
||||
|
||||
return com.ch
|
||||
}
|
||||
|
||||
// GetPoint is called by a QueryStatement and retrieves a point sent by the associated InsertStatement
|
||||
func (st *StressTest) GetPoint(name, precision string) models.Point {
|
||||
p := st.communes[name].point(precision)
|
||||
|
||||
// Function needs to return a point. Panic if it doesn't
|
||||
if p == nil {
|
||||
log.Fatal("Commune not returning point")
|
||||
}
|
||||
|
||||
return p
|
||||
}
|
57
vendor/github.com/influxdata/influxdb/stress/v2/stress_client/commune_test.go
generated
vendored
Normal file
57
vendor/github.com/influxdata/influxdb/stress/v2/stress_client/commune_test.go
generated
vendored
Normal file
@@ -0,0 +1,57 @@
|
||||
package stressClient
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestCommunePoint(t *testing.T) {
|
||||
comm := newCommune(5)
|
||||
pt := "write,tag=tagVal fooField=5 1460912595"
|
||||
comm.ch <- pt
|
||||
point := comm.point("s")
|
||||
if string(point.Name()) != "write" {
|
||||
t.Errorf("expected: write\ngot: %v", string(point.Name()))
|
||||
}
|
||||
if point.Tags().GetString("tag") != "tagVal" {
|
||||
t.Errorf("expected: tagVal\ngot: %v", point.Tags().GetString("tag"))
|
||||
}
|
||||
fields, err := point.Fields()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if int(fields["fooField"].(float64)) != 5 {
|
||||
t.Errorf("expected: 5\ngot: %v\n", fields["fooField"])
|
||||
}
|
||||
// Make sure commune returns the prev point
|
||||
comm.ch <- ""
|
||||
point = comm.point("s")
|
||||
if string(point.Name()) != "write" {
|
||||
t.Errorf("expected: write\ngot: %v", string(point.Name()))
|
||||
}
|
||||
if point.Tags().GetString("tag") != "tagVal" {
|
||||
t.Errorf("expected: tagVal\ngot: %v", point.Tags().GetString("tag"))
|
||||
}
|
||||
if int(fields["fooField"].(float64)) != 5 {
|
||||
t.Errorf("expected: 5\ngot: %v\n", fields["fooField"])
|
||||
}
|
||||
}
|
||||
|
||||
func TestSetCommune(t *testing.T) {
|
||||
sf, _, _ := NewTestStressTest()
|
||||
ch := sf.SetCommune("foo_name")
|
||||
ch <- "write,tag=tagVal fooField=5 1460912595"
|
||||
pt := sf.GetPoint("foo_name", "s")
|
||||
if string(pt.Name()) != "write" {
|
||||
t.Errorf("expected: write\ngot: %v", string(pt.Name()))
|
||||
}
|
||||
if pt.Tags().GetString("tag") != "tagVal" {
|
||||
t.Errorf("expected: tagVal\ngot: %v", pt.Tags().GetString("tag"))
|
||||
}
|
||||
fields, err := pt.Fields()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if int(fields["fooField"].(float64)) != 5 {
|
||||
t.Errorf("expected: 5\ngot: %v\n", fields["fooField"])
|
||||
}
|
||||
}
|
19
vendor/github.com/influxdata/influxdb/stress/v2/stress_client/directive.go
generated
vendored
Normal file
19
vendor/github.com/influxdata/influxdb/stress/v2/stress_client/directive.go
generated
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
package stressClient
|
||||
|
||||
// Directive is a struct to enable communication between SetStatements and the stressClient backend
|
||||
// Directives change state for the stress test
|
||||
type Directive struct {
|
||||
Property string
|
||||
Value string
|
||||
Tracer *Tracer
|
||||
}
|
||||
|
||||
// NewDirective creates a new instance of a Directive with the appropriate state variable to change
|
||||
func NewDirective(property string, value string, tracer *Tracer) Directive {
|
||||
d := Directive{
|
||||
Property: property,
|
||||
Value: value,
|
||||
Tracer: tracer,
|
||||
}
|
||||
return d
|
||||
}
|
20
vendor/github.com/influxdata/influxdb/stress/v2/stress_client/directive_test.go
generated
vendored
Normal file
20
vendor/github.com/influxdata/influxdb/stress/v2/stress_client/directive_test.go
generated
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
package stressClient
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestNewDirective(t *testing.T) {
|
||||
tr := NewTracer(map[string]string{})
|
||||
prop := "foo_prop"
|
||||
val := "foo_value"
|
||||
dir := NewDirective(prop, val, tr)
|
||||
got := dir.Property
|
||||
if prop != got {
|
||||
t.Errorf("expected: %v\ngot: %v\n", prop, got)
|
||||
}
|
||||
got = dir.Value
|
||||
if val != got {
|
||||
t.Errorf("expected: %v\ngot: %v\n", val, got)
|
||||
}
|
||||
}
|
22
vendor/github.com/influxdata/influxdb/stress/v2/stress_client/package.go
generated
vendored
Normal file
22
vendor/github.com/influxdata/influxdb/stress/v2/stress_client/package.go
generated
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
package stressClient
|
||||
|
||||
// Package is a struct to enable communication between InsertStatements, QueryStatements and InfluxQLStatements and the stressClient backend
|
||||
// Packages carry either writes or queries in the []byte that makes up the Body
|
||||
type Package struct {
|
||||
T Type
|
||||
Body []byte
|
||||
StatementID string
|
||||
Tracer *Tracer
|
||||
}
|
||||
|
||||
// NewPackage creates a new package with the appropriate payload
|
||||
func NewPackage(t Type, body []byte, statementID string, tracer *Tracer) Package {
|
||||
p := Package{
|
||||
T: t,
|
||||
Body: body,
|
||||
StatementID: statementID,
|
||||
Tracer: tracer,
|
||||
}
|
||||
|
||||
return p
|
||||
}
|
16
vendor/github.com/influxdata/influxdb/stress/v2/stress_client/package_test.go
generated
vendored
Normal file
16
vendor/github.com/influxdata/influxdb/stress/v2/stress_client/package_test.go
generated
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
package stressClient
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestNewPackage(t *testing.T) {
|
||||
qry := []byte("SELECT * FROM foo")
|
||||
statementID := "foo_id"
|
||||
tr := NewTracer(map[string]string{})
|
||||
pkg := NewPackage(Query, qry, statementID, tr)
|
||||
got := string(pkg.Body)
|
||||
if string(qry) != got {
|
||||
t.Errorf("expected: %v\ngot: %v\n", qry, got)
|
||||
}
|
||||
}
|
95
vendor/github.com/influxdata/influxdb/stress/v2/stress_client/reporting.go
generated
vendored
Normal file
95
vendor/github.com/influxdata/influxdb/stress/v2/stress_client/reporting.go
generated
vendored
Normal file
@@ -0,0 +1,95 @@
|
||||
package stressClient
|
||||
|
||||
import (
|
||||
"log"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
influx "github.com/influxdata/influxdb/client/v2"
|
||||
)
|
||||
|
||||
// reporting.go contains functions to emit tags and points from various parts of stressClient
|
||||
// These points are then written to the ("_%v", sf.TestName) database
|
||||
|
||||
// These are the tags that stressClient adds to any response points
|
||||
func (sc *stressClient) tags(statementID string) map[string]string {
|
||||
tags := map[string]string{
|
||||
"number_targets": fmtInt(len(sc.addresses)),
|
||||
"precision": sc.precision,
|
||||
"writers": fmtInt(sc.wconc),
|
||||
"readers": fmtInt(sc.qconc),
|
||||
"test_id": sc.testID,
|
||||
"statement_id": statementID,
|
||||
"write_interval": sc.wdelay,
|
||||
"query_interval": sc.qdelay,
|
||||
}
|
||||
return tags
|
||||
}
|
||||
|
||||
// These are the tags that the StressTest adds to any response points
|
||||
func (st *StressTest) tags() map[string]string {
|
||||
tags := map[string]string{
|
||||
"precision": st.Precision,
|
||||
"batch_size": fmtInt(st.BatchSize),
|
||||
}
|
||||
return tags
|
||||
}
|
||||
|
||||
// This function makes a *client.Point for reporting on writes
|
||||
func (sc *stressClient) writePoint(retries int, statementID string, statusCode int, responseTime time.Duration, addedTags map[string]string, writeBytes int) *influx.Point {
|
||||
|
||||
tags := sumTags(sc.tags(statementID), addedTags)
|
||||
|
||||
fields := map[string]interface{}{
|
||||
"status_code": statusCode,
|
||||
"response_time_ns": responseTime.Nanoseconds(),
|
||||
"num_bytes": writeBytes,
|
||||
}
|
||||
|
||||
point, err := influx.NewPoint("write", tags, fields, time.Now())
|
||||
|
||||
if err != nil {
|
||||
log.Fatalf("Error creating write results point\n error: %v\n", err)
|
||||
}
|
||||
|
||||
return point
|
||||
}
|
||||
|
||||
// This function makes a *client.Point for reporting on queries
|
||||
func (sc *stressClient) queryPoint(statementID string, body []byte, statusCode int, responseTime time.Duration, addedTags map[string]string) *influx.Point {
|
||||
|
||||
tags := sumTags(sc.tags(statementID), addedTags)
|
||||
|
||||
fields := map[string]interface{}{
|
||||
"status_code": statusCode,
|
||||
"num_bytes": len(body),
|
||||
"response_time_ns": responseTime.Nanoseconds(),
|
||||
}
|
||||
|
||||
point, err := influx.NewPoint("query", tags, fields, time.Now())
|
||||
|
||||
if err != nil {
|
||||
log.Fatalf("Error creating query results point\n error: %v\n", err)
|
||||
}
|
||||
|
||||
return point
|
||||
}
|
||||
|
||||
// Adds two map[string]string together
|
||||
func sumTags(tags1, tags2 map[string]string) map[string]string {
|
||||
tags := make(map[string]string)
|
||||
// Add all tags from first map to return map
|
||||
for k, v := range tags1 {
|
||||
tags[k] = v
|
||||
}
|
||||
// Add all tags from second map to return map
|
||||
for k, v := range tags2 {
|
||||
tags[k] = v
|
||||
}
|
||||
return tags
|
||||
}
|
||||
|
||||
// Turns an int into a string
|
||||
func fmtInt(i int) string {
|
||||
return strconv.FormatInt(int64(i), 10)
|
||||
}
|
100
vendor/github.com/influxdata/influxdb/stress/v2/stress_client/reporting_test.go
generated
vendored
Normal file
100
vendor/github.com/influxdata/influxdb/stress/v2/stress_client/reporting_test.go
generated
vendored
Normal file
@@ -0,0 +1,100 @@
|
||||
package stressClient
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestNewStressClientTags(t *testing.T) {
|
||||
pe, _, _ := newTestStressClient("localhost:8086")
|
||||
tags := pe.tags("foo_id")
|
||||
expected := fmtInt(len(pe.addresses))
|
||||
got := tags["number_targets"]
|
||||
if expected != got {
|
||||
t.Errorf("expected: %v\ngot: %v\n", expected, got)
|
||||
}
|
||||
expected = pe.precision
|
||||
got = tags["precision"]
|
||||
if expected != got {
|
||||
t.Errorf("expected: %v\ngot: %v\n", expected, got)
|
||||
}
|
||||
expected = pe.wdelay
|
||||
got = tags["write_interval"]
|
||||
if expected != got {
|
||||
t.Errorf("expected: %v\ngot: %v\n", expected, got)
|
||||
}
|
||||
expected = "foo_id"
|
||||
got = tags["statement_id"]
|
||||
if expected != got {
|
||||
t.Errorf("expected: %v\ngot: %v\n", expected, got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewStressTestTags(t *testing.T) {
|
||||
sf, _, _ := NewTestStressTest()
|
||||
tags := sf.tags()
|
||||
expected := sf.Precision
|
||||
got := tags["precision"]
|
||||
if expected != got {
|
||||
t.Errorf("expected: %v\ngot: %v\n", expected, got)
|
||||
}
|
||||
expected = fmtInt(sf.BatchSize)
|
||||
got = tags["batch_size"]
|
||||
if expected != got {
|
||||
t.Errorf("expected: %v\ngot: %v\n", expected, got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestWritePoint(t *testing.T) {
|
||||
pe, _, _ := newTestStressClient("localhost:8086")
|
||||
statementID := "foo_id"
|
||||
responseCode := 200
|
||||
responseTime := time.Duration(10 * time.Millisecond)
|
||||
addedTags := map[string]string{"foo_tag": "foo_tag_value"}
|
||||
writeBytes := 28051
|
||||
pt := pe.writePoint(1, statementID, responseCode, responseTime, addedTags, writeBytes)
|
||||
got := pt.Tags()["statement_id"]
|
||||
if statementID != got {
|
||||
t.Errorf("expected: %v\ngot: %v\n", statementID, got)
|
||||
}
|
||||
fields, err := pt.Fields()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
got2 := int(fields["status_code"].(int64))
|
||||
if responseCode != got2 {
|
||||
t.Errorf("expected: %v\ngot: %v\n", responseCode, got2)
|
||||
}
|
||||
expected := "write"
|
||||
got = pt.Name()
|
||||
if expected != got {
|
||||
t.Errorf("expected: %v\ngot: %v\n", expected, got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestQueryPoint(t *testing.T) {
|
||||
pe, _, _ := newTestStressClient("localhost:8086")
|
||||
statementID := "foo_id"
|
||||
responseCode := 200
|
||||
body := []byte{12}
|
||||
responseTime := time.Duration(10 * time.Millisecond)
|
||||
addedTags := map[string]string{"foo_tag": "foo_tag_value"}
|
||||
pt := pe.queryPoint(statementID, body, responseCode, responseTime, addedTags)
|
||||
got := pt.Tags()["statement_id"]
|
||||
if statementID != got {
|
||||
t.Errorf("expected: %v\ngot: %v\n", statementID, got)
|
||||
}
|
||||
fields, err := pt.Fields()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
got2 := int(fields["status_code"].(int64))
|
||||
if responseCode != got2 {
|
||||
t.Errorf("expected: %v\ngot: %v\n", responseCode, got2)
|
||||
}
|
||||
expected := "query"
|
||||
got = pt.Name()
|
||||
if expected != got {
|
||||
t.Errorf("expected: %v\ngot: %v\n", expected, got)
|
||||
}
|
||||
}
|
50
vendor/github.com/influxdata/influxdb/stress/v2/stress_client/response.go
generated
vendored
Normal file
50
vendor/github.com/influxdata/influxdb/stress/v2/stress_client/response.go
generated
vendored
Normal file
@@ -0,0 +1,50 @@
|
||||
package stressClient
|
||||
|
||||
import (
|
||||
"log"
|
||||
|
||||
influx "github.com/influxdata/influxdb/client/v2"
|
||||
)
|
||||
|
||||
// Response holds data scraped from InfluxDB HTTP responses turned into a *influx.Point for reporting
|
||||
// See reporting.go for more information
|
||||
// The Tracer contains a wait group sent from the statement. It needs to be decremented when the Response is consumed
|
||||
type Response struct {
|
||||
Point *influx.Point
|
||||
Tracer *Tracer
|
||||
}
|
||||
|
||||
// NewResponse creates a new instance of Response
|
||||
func NewResponse(pt *influx.Point, tr *Tracer) Response {
|
||||
return Response{
|
||||
Point: pt,
|
||||
Tracer: tr,
|
||||
}
|
||||
}
|
||||
|
||||
// AddTags adds additional tags to the point held in Response and returns the point
|
||||
func (resp Response) AddTags(newTags map[string]string) (*influx.Point, error) {
|
||||
|
||||
// Pull off the current tags
|
||||
tags := resp.Point.Tags()
|
||||
|
||||
// Add the new tags to the current tags
|
||||
for tag, tagValue := range newTags {
|
||||
tags[tag] = tagValue
|
||||
}
|
||||
|
||||
// Make a new point
|
||||
fields, err := resp.Point.Fields()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
}
|
||||
pt, err := influx.NewPoint(resp.Point.Name(), tags, fields, resp.Point.Time())
|
||||
|
||||
// panic on error
|
||||
if err != nil {
|
||||
log.Fatalf("Error adding tags to response point\n point: %v\n tags:%v\n error: %v\n", resp.Point, newTags, err)
|
||||
}
|
||||
|
||||
return pt, nil
|
||||
}
|
20
vendor/github.com/influxdata/influxdb/stress/v2/stress_client/response_test.go
generated
vendored
Normal file
20
vendor/github.com/influxdata/influxdb/stress/v2/stress_client/response_test.go
generated
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
package stressClient
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestNewResponse(t *testing.T) {
|
||||
pt := NewBlankTestPoint()
|
||||
tr := NewTracer(map[string]string{})
|
||||
r := NewResponse(pt, tr)
|
||||
expected := "another_tag_value"
|
||||
test, err := r.AddTags(map[string]string{"another_tag": "another_tag_value"})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
got := test.Tags()["another_tag"]
|
||||
if expected != got {
|
||||
t.Errorf("expected: %v\ngot: %v\n", expected, got)
|
||||
}
|
||||
}
|
175
vendor/github.com/influxdata/influxdb/stress/v2/stress_client/stressTest.go
generated
vendored
Normal file
175
vendor/github.com/influxdata/influxdb/stress/v2/stress_client/stressTest.go
generated
vendored
Normal file
@@ -0,0 +1,175 @@
|
||||
package stressClient
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"sync"
|
||||
|
||||
influx "github.com/influxdata/influxdb/client/v2"
|
||||
)
|
||||
|
||||
// NewStressTest creates the backend for the stress test
|
||||
func NewStressTest() *StressTest {
|
||||
|
||||
packageCh := make(chan Package, 0)
|
||||
directiveCh := make(chan Directive, 0)
|
||||
responseCh := make(chan Response, 0)
|
||||
|
||||
clnt, _ := influx.NewHTTPClient(influx.HTTPConfig{
|
||||
Addr: fmt.Sprintf("http://%v/", "localhost:8086"),
|
||||
})
|
||||
|
||||
s := &StressTest{
|
||||
TestDB: "_stressTest",
|
||||
Precision: "s",
|
||||
StartDate: "2016-01-02",
|
||||
BatchSize: 5000,
|
||||
|
||||
packageChan: packageCh,
|
||||
directiveChan: directiveCh,
|
||||
|
||||
ResultsClient: clnt,
|
||||
ResultsChan: responseCh,
|
||||
communes: make(map[string]*commune),
|
||||
TestID: randStr(10),
|
||||
}
|
||||
|
||||
// Start the client service
|
||||
startStressClient(packageCh, directiveCh, responseCh, s.TestID)
|
||||
|
||||
// Listen for Results coming in
|
||||
s.resultsListen()
|
||||
|
||||
return s
|
||||
}
|
||||
|
||||
// NewTestStressTest returns a StressTest to be used for testing Statements
|
||||
func NewTestStressTest() (*StressTest, chan Package, chan Directive) {
|
||||
|
||||
packageCh := make(chan Package, 0)
|
||||
directiveCh := make(chan Directive, 0)
|
||||
|
||||
s := &StressTest{
|
||||
TestDB: "_stressTest",
|
||||
Precision: "s",
|
||||
StartDate: "2016-01-02",
|
||||
BatchSize: 5000,
|
||||
|
||||
directiveChan: directiveCh,
|
||||
packageChan: packageCh,
|
||||
|
||||
communes: make(map[string]*commune),
|
||||
TestID: randStr(10),
|
||||
}
|
||||
|
||||
return s, packageCh, directiveCh
|
||||
}
|
||||
|
||||
// The StressTest is the Statement facing API that consumes Statement output and coordinates the test results
|
||||
type StressTest struct {
|
||||
TestID string
|
||||
TestDB string
|
||||
|
||||
Precision string
|
||||
StartDate string
|
||||
BatchSize int
|
||||
|
||||
sync.WaitGroup
|
||||
sync.Mutex
|
||||
|
||||
packageChan chan<- Package
|
||||
directiveChan chan<- Directive
|
||||
|
||||
ResultsChan chan Response
|
||||
communes map[string]*commune
|
||||
ResultsClient influx.Client
|
||||
}
|
||||
|
||||
// SendPackage is the public facing API for to send Queries and Points
|
||||
func (st *StressTest) SendPackage(p Package) {
|
||||
st.packageChan <- p
|
||||
}
|
||||
|
||||
// SendDirective is the public facing API to set state variables in the test
|
||||
func (st *StressTest) SendDirective(d Directive) {
|
||||
st.directiveChan <- d
|
||||
}
|
||||
|
||||
// Starts a go routine that listens for Results
|
||||
func (st *StressTest) resultsListen() {
|
||||
st.createDatabase(st.TestDB)
|
||||
go func() {
|
||||
bp := st.NewResultsPointBatch()
|
||||
for resp := range st.ResultsChan {
|
||||
switch resp.Point.Name() {
|
||||
case "done":
|
||||
st.ResultsClient.Write(bp)
|
||||
resp.Tracer.Done()
|
||||
default:
|
||||
// Add the StressTest tags
|
||||
pt, err := resp.AddTags(st.tags())
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
// Add the point to the batch
|
||||
bp = st.batcher(pt, bp)
|
||||
resp.Tracer.Done()
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
// NewResultsPointBatch creates a new batch of points for the results
|
||||
func (st *StressTest) NewResultsPointBatch() influx.BatchPoints {
|
||||
bp, _ := influx.NewBatchPoints(influx.BatchPointsConfig{
|
||||
Database: st.TestDB,
|
||||
Precision: "ns",
|
||||
})
|
||||
return bp
|
||||
}
|
||||
|
||||
// Batches incoming Result.Point and sends them if the batch reaches 5k in size
|
||||
func (st *StressTest) batcher(pt *influx.Point, bp influx.BatchPoints) influx.BatchPoints {
|
||||
if len(bp.Points()) <= 5000 {
|
||||
bp.AddPoint(pt)
|
||||
} else {
|
||||
err := st.ResultsClient.Write(bp)
|
||||
if err != nil {
|
||||
log.Fatalf("Error writing performance stats\n error: %v\n", err)
|
||||
}
|
||||
bp = st.NewResultsPointBatch()
|
||||
}
|
||||
return bp
|
||||
}
|
||||
|
||||
// Convinence database creation function
|
||||
func (st *StressTest) createDatabase(db string) {
|
||||
query := fmt.Sprintf("CREATE DATABASE %v", db)
|
||||
res, err := st.ResultsClient.Query(influx.Query{Command: query})
|
||||
if err != nil {
|
||||
log.Fatalf("error: no running influx server at localhost:8086")
|
||||
if res.Error() != nil {
|
||||
log.Fatalf("error: no running influx server at localhost:8086")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// GetStatementResults is a convinence function for fetching all results given a StatementID
|
||||
func (st *StressTest) GetStatementResults(sID, t string) (res []influx.Result) {
|
||||
qryStr := fmt.Sprintf(`SELECT * FROM "%v" WHERE statement_id = '%v'`, t, sID)
|
||||
return st.queryTestResults(qryStr)
|
||||
}
|
||||
|
||||
// Runs given qry on the test results database and returns the results or nil in case of error
|
||||
func (st *StressTest) queryTestResults(qry string) (res []influx.Result) {
|
||||
response, err := st.ResultsClient.Query(influx.Query{Command: qry, Database: st.TestDB})
|
||||
if err == nil {
|
||||
if response.Error() != nil {
|
||||
log.Fatalf("Error sending results query\n error: %v\n", response.Error())
|
||||
}
|
||||
}
|
||||
if response.Results[0].Series == nil {
|
||||
return nil
|
||||
}
|
||||
return response.Results
|
||||
}
|
32
vendor/github.com/influxdata/influxdb/stress/v2/stress_client/stressTest_test.go
generated
vendored
Normal file
32
vendor/github.com/influxdata/influxdb/stress/v2/stress_client/stressTest_test.go
generated
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
package stressClient
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
influx "github.com/influxdata/influxdb/client/v2"
|
||||
)
|
||||
|
||||
func NewBlankTestPoint() *influx.Point {
|
||||
meas := "measurement"
|
||||
tags := map[string]string{"fooTag": "fooTagValue"}
|
||||
fields := map[string]interface{}{"value": 5920}
|
||||
utc, _ := time.LoadLocation("UTC")
|
||||
timestamp := time.Date(2016, time.Month(4), 20, 0, 0, 0, 0, utc)
|
||||
pt, _ := influx.NewPoint(meas, tags, fields, timestamp)
|
||||
return pt
|
||||
}
|
||||
|
||||
func TestStressTestBatcher(t *testing.T) {
|
||||
sf, _, _ := NewTestStressTest()
|
||||
bpconf := influx.BatchPointsConfig{
|
||||
Database: sf.TestDB,
|
||||
Precision: "ns",
|
||||
}
|
||||
bp, _ := influx.NewBatchPoints(bpconf)
|
||||
pt := NewBlankTestPoint()
|
||||
bp = sf.batcher(pt, bp)
|
||||
if len(bp.Points()) != 1 {
|
||||
t.Fail()
|
||||
}
|
||||
}
|
175
vendor/github.com/influxdata/influxdb/stress/v2/stress_client/stress_client.go
generated
vendored
Normal file
175
vendor/github.com/influxdata/influxdb/stress/v2/stress_client/stress_client.go
generated
vendored
Normal file
@@ -0,0 +1,175 @@
|
||||
package stressClient
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// Type refers to the different Package types
|
||||
type Type int
|
||||
|
||||
// There are two package types, Write and Query
|
||||
const (
|
||||
Write Type = iota
|
||||
Query
|
||||
)
|
||||
|
||||
func startStressClient(packageCh <-chan Package, directiveCh <-chan Directive, responseCh chan<- Response, testID string) {
|
||||
|
||||
c := &stressClient{
|
||||
testID: testID,
|
||||
|
||||
addresses: []string{"localhost:8086"},
|
||||
ssl: false,
|
||||
username: "",
|
||||
password: "",
|
||||
precision: "ns",
|
||||
database: "stress",
|
||||
startDate: "2016-01-01",
|
||||
qdelay: "0s",
|
||||
wdelay: "0s",
|
||||
|
||||
wconc: 10,
|
||||
qconc: 5,
|
||||
|
||||
packageChan: packageCh,
|
||||
directiveChan: directiveCh,
|
||||
|
||||
responseChan: responseCh,
|
||||
}
|
||||
// start listening for writes and queries
|
||||
go c.listen()
|
||||
// start listening for state changes
|
||||
go c.directiveListen()
|
||||
}
|
||||
|
||||
type stressClient struct {
|
||||
testID string
|
||||
|
||||
// State for the Stress Test
|
||||
addresses []string
|
||||
precision string
|
||||
startDate string
|
||||
database string
|
||||
wdelay string
|
||||
qdelay string
|
||||
username string
|
||||
password string
|
||||
ssl bool
|
||||
|
||||
// Channels from statements
|
||||
packageChan <-chan Package
|
||||
directiveChan <-chan Directive
|
||||
|
||||
// Response channel
|
||||
responseChan chan<- Response
|
||||
|
||||
// Concurrency utilities
|
||||
sync.WaitGroup
|
||||
sync.Mutex
|
||||
|
||||
// Concurrency Limit for Writes and Reads
|
||||
wconc int
|
||||
qconc int
|
||||
|
||||
// Manage Read and Write concurrency seperately
|
||||
wc *ConcurrencyLimiter
|
||||
rc *ConcurrencyLimiter
|
||||
}
|
||||
|
||||
// NewTestStressClient returns a blank stressClient for testing
|
||||
func newTestStressClient(url string) (*stressClient, chan Directive, chan Package) {
|
||||
pkgChan := make(chan Package)
|
||||
dirChan := make(chan Directive)
|
||||
pe := &stressClient{
|
||||
testID: "foo_id",
|
||||
addresses: []string{url},
|
||||
precision: "s",
|
||||
startDate: "2016-01-01",
|
||||
database: "fooDatabase",
|
||||
wdelay: "50ms",
|
||||
qdelay: "50ms",
|
||||
ssl: false,
|
||||
username: "",
|
||||
password: "",
|
||||
wconc: 5,
|
||||
qconc: 5,
|
||||
packageChan: pkgChan,
|
||||
directiveChan: dirChan,
|
||||
wc: NewConcurrencyLimiter(1),
|
||||
rc: NewConcurrencyLimiter(1),
|
||||
}
|
||||
return pe, dirChan, pkgChan
|
||||
}
|
||||
|
||||
// stressClient starts listening for Packages on the main channel
|
||||
func (sc *stressClient) listen() {
|
||||
defer sc.Wait()
|
||||
sc.wc = NewConcurrencyLimiter(sc.wconc)
|
||||
sc.rc = NewConcurrencyLimiter(sc.qconc)
|
||||
l := NewConcurrencyLimiter((sc.wconc + sc.qconc) * 2)
|
||||
counter := 0
|
||||
for p := range sc.packageChan {
|
||||
l.Increment()
|
||||
go func(p Package) {
|
||||
defer l.Decrement()
|
||||
switch p.T {
|
||||
case Write:
|
||||
sc.spinOffWritePackage(p, (counter % len(sc.addresses)))
|
||||
case Query:
|
||||
sc.spinOffQueryPackage(p, (counter % len(sc.addresses)))
|
||||
}
|
||||
}(p)
|
||||
counter++
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Set handles all SET requests for test state
|
||||
func (sc *stressClient) directiveListen() {
|
||||
for d := range sc.directiveChan {
|
||||
sc.Lock()
|
||||
switch d.Property {
|
||||
// addresses is a []string of target InfluxDB instance(s) for the test
|
||||
// comes in as a "|" seperated array of addresses
|
||||
case "addresses":
|
||||
addr := strings.Split(d.Value, "|")
|
||||
sc.addresses = addr
|
||||
// percison is the write precision for InfluxDB
|
||||
case "precision":
|
||||
sc.precision = d.Value
|
||||
// writeinterval is an optional delay between batches
|
||||
case "writeinterval":
|
||||
sc.wdelay = d.Value
|
||||
// queryinterval is an optional delay between the batches
|
||||
case "queryinterval":
|
||||
sc.qdelay = d.Value
|
||||
// database is the InfluxDB database to target for both writes and queries
|
||||
case "database":
|
||||
sc.database = d.Value
|
||||
// username for the target database
|
||||
case "username":
|
||||
sc.username = d.Value
|
||||
// username for the target database
|
||||
case "password":
|
||||
sc.password = d.Value
|
||||
// use https if sent true
|
||||
case "ssl":
|
||||
if d.Value == "true" {
|
||||
sc.ssl = true
|
||||
}
|
||||
// concurrency is the number concurrent writers to the database
|
||||
case "writeconcurrency":
|
||||
conc := parseInt(d.Value)
|
||||
sc.wconc = conc
|
||||
sc.wc.NewMax(conc)
|
||||
// concurrentqueries is the number of concurrent queriers database
|
||||
case "queryconcurrency":
|
||||
conc := parseInt(d.Value)
|
||||
sc.qconc = conc
|
||||
sc.rc.NewMax(conc)
|
||||
}
|
||||
d.Tracer.Done()
|
||||
sc.Unlock()
|
||||
}
|
||||
}
|
74
vendor/github.com/influxdata/influxdb/stress/v2/stress_client/stress_client_query.go
generated
vendored
Normal file
74
vendor/github.com/influxdata/influxdb/stress/v2/stress_client/stress_client_query.go
generated
vendored
Normal file
@@ -0,0 +1,74 @@
|
||||
package stressClient
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"time"
|
||||
)
|
||||
|
||||
func (sc *stressClient) spinOffQueryPackage(p Package, serv int) {
|
||||
sc.Add(1)
|
||||
sc.rc.Increment()
|
||||
go func() {
|
||||
// Send the query
|
||||
sc.prepareQuerySend(p, serv)
|
||||
sc.Done()
|
||||
sc.rc.Decrement()
|
||||
}()
|
||||
}
|
||||
|
||||
// Prepares to send the GET request
|
||||
func (sc *stressClient) prepareQuerySend(p Package, serv int) {
|
||||
|
||||
var queryTemplate string
|
||||
if sc.ssl {
|
||||
queryTemplate = "https://%v/query?db=%v&q=%v&u=%v&p=%v"
|
||||
} else {
|
||||
queryTemplate = "http://%v/query?db=%v&q=%v&u=%v&p=%v"
|
||||
}
|
||||
queryURL := fmt.Sprintf(queryTemplate, sc.addresses[serv], sc.database, url.QueryEscape(string(p.Body)), sc.username, sc.password)
|
||||
|
||||
// Send the query
|
||||
sc.makeGet(queryURL, p.StatementID, p.Tracer)
|
||||
|
||||
// Query Interval enforcement
|
||||
qi, _ := time.ParseDuration(sc.qdelay)
|
||||
time.Sleep(qi)
|
||||
}
|
||||
|
||||
// Sends the GET request, reads it, and handles errors
|
||||
func (sc *stressClient) makeGet(addr, statementID string, tr *Tracer) {
|
||||
|
||||
// Make GET request
|
||||
t := time.Now()
|
||||
resp, err := http.Get(addr)
|
||||
elapsed := time.Since(t)
|
||||
|
||||
if err != nil {
|
||||
log.Printf("Error making Query HTTP request\n error: %v\n", err)
|
||||
}
|
||||
|
||||
defer resp.Body.Close()
|
||||
|
||||
// Read body and return it for Reporting
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
|
||||
if err != nil {
|
||||
log.Fatalf("Error reading Query response body\n error: %v\n", err)
|
||||
}
|
||||
|
||||
if resp.StatusCode != 200 {
|
||||
log.Printf("Query returned non 200 status\n status: %v\n error: %v\n", resp.StatusCode, string(body))
|
||||
}
|
||||
|
||||
// Send the response
|
||||
sc.responseChan <- NewResponse(sc.queryPoint(statementID, body, resp.StatusCode, elapsed, tr.Tags), tr)
|
||||
}
|
||||
|
||||
func success(r *http.Response) bool {
|
||||
// ADD success for tcp, udp, etc
|
||||
return r != nil && (r.StatusCode == 204 || r.StatusCode == 200)
|
||||
}
|
112
vendor/github.com/influxdata/influxdb/stress/v2/stress_client/stress_client_write.go
generated
vendored
Normal file
112
vendor/github.com/influxdata/influxdb/stress/v2/stress_client/stress_client_write.go
generated
vendored
Normal file
@@ -0,0 +1,112 @@
|
||||
package stressClient
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"time"
|
||||
)
|
||||
|
||||
// ###############################################
|
||||
// A selection of methods to manage the write path
|
||||
// ###############################################
|
||||
|
||||
// Packages up Package from channel in goroutine
|
||||
func (sc *stressClient) spinOffWritePackage(p Package, serv int) {
|
||||
sc.Add(1)
|
||||
sc.wc.Increment()
|
||||
go func() {
|
||||
sc.retry(p, time.Duration(time.Nanosecond), serv)
|
||||
sc.Done()
|
||||
sc.wc.Decrement()
|
||||
}()
|
||||
}
|
||||
|
||||
// Implements backoff and retry logic for 500 responses
|
||||
func (sc *stressClient) retry(p Package, backoff time.Duration, serv int) {
|
||||
|
||||
// Set Backoff Interval to 500ms
|
||||
backoffInterval := time.Duration(500 * time.Millisecond)
|
||||
|
||||
// Arithmetic backoff for kicks
|
||||
bo := backoff + backoffInterval
|
||||
|
||||
// Make the write request
|
||||
resp, elapsed, err := sc.prepareWrite(p.Body, serv)
|
||||
|
||||
// Find number of times request has been retried
|
||||
numBackoffs := int(bo/backoffInterval) - 1
|
||||
|
||||
// On 500 responses, resp == nil. This logic keeps program for panicing
|
||||
var statusCode int
|
||||
|
||||
if resp == nil {
|
||||
statusCode = 500
|
||||
} else {
|
||||
statusCode = resp.StatusCode
|
||||
}
|
||||
|
||||
// Make a point for reporting
|
||||
point := sc.writePoint(numBackoffs, p.StatementID, statusCode, elapsed, p.Tracer.Tags, len(p.Body))
|
||||
|
||||
// Send the Response(point, tracer)
|
||||
sc.responseChan <- NewResponse(point, p.Tracer)
|
||||
|
||||
// BatchInterval enforcement
|
||||
bi, _ := time.ParseDuration(sc.wdelay)
|
||||
time.Sleep(bi)
|
||||
|
||||
// Retry if the statusCode was not 204 or the err != nil
|
||||
if !(statusCode == 204) || err != nil {
|
||||
// Increment the *Tracer waitgroup if we are going to retry the request
|
||||
p.Tracer.Add(1)
|
||||
// Log the error if there is one
|
||||
fmt.Println(err)
|
||||
// Backoff enforcement
|
||||
time.Sleep(bo)
|
||||
sc.retry(p, bo, serv)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Prepares to send the POST request
|
||||
func (sc *stressClient) prepareWrite(points []byte, serv int) (*http.Response, time.Duration, error) {
|
||||
|
||||
// Construct address string
|
||||
var writeTemplate string
|
||||
if sc.ssl {
|
||||
writeTemplate = "https://%v/write?db=%v&precision=%v&u=%v&p=%v"
|
||||
} else {
|
||||
writeTemplate = "http://%v/write?db=%v&precision=%v&u=%v&p=%v"
|
||||
}
|
||||
address := fmt.Sprintf(writeTemplate, sc.addresses[serv], sc.database, sc.precision, sc.username, sc.password)
|
||||
|
||||
// Start timer
|
||||
t := time.Now()
|
||||
resp, err := makePost(address, bytes.NewBuffer(points))
|
||||
elapsed := time.Since(t)
|
||||
|
||||
return resp, elapsed, err
|
||||
}
|
||||
|
||||
// Send POST request, read it, and handle errors
|
||||
func makePost(url string, points io.Reader) (*http.Response, error) {
|
||||
|
||||
resp, err := http.Post(url, "text/plain", points)
|
||||
|
||||
if err != nil {
|
||||
return resp, fmt.Errorf("Error making write POST request\n error: %v\n url: %v\n", err, url)
|
||||
}
|
||||
|
||||
body, _ := ioutil.ReadAll(resp.Body)
|
||||
|
||||
if resp.StatusCode != 204 {
|
||||
return resp, fmt.Errorf("Write returned non-204 status code\n StatusCode: %v\n InfluxDB Error: %v\n", resp.StatusCode, string(body))
|
||||
}
|
||||
|
||||
resp.Body.Close()
|
||||
|
||||
return resp, nil
|
||||
}
|
19
vendor/github.com/influxdata/influxdb/stress/v2/stress_client/tracer.go
generated
vendored
Normal file
19
vendor/github.com/influxdata/influxdb/stress/v2/stress_client/tracer.go
generated
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
package stressClient
|
||||
|
||||
import (
|
||||
"sync"
|
||||
)
|
||||
|
||||
// The Tracer carrys tags and a waitgroup from the statements through the package life cycle
|
||||
type Tracer struct {
|
||||
Tags map[string]string
|
||||
|
||||
sync.WaitGroup
|
||||
}
|
||||
|
||||
// NewTracer returns a Tracer with tags attached
|
||||
func NewTracer(tags map[string]string) *Tracer {
|
||||
return &Tracer{
|
||||
Tags: tags,
|
||||
}
|
||||
}
|
17
vendor/github.com/influxdata/influxdb/stress/v2/stress_client/tracer_test.go
generated
vendored
Normal file
17
vendor/github.com/influxdata/influxdb/stress/v2/stress_client/tracer_test.go
generated
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
package stressClient
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestNewTracer(t *testing.T) {
|
||||
tagValue := "foo_tag_value"
|
||||
tracer := NewTracer(map[string]string{"foo_tag_key": tagValue})
|
||||
got := tracer.Tags["foo_tag_key"]
|
||||
if got != tagValue {
|
||||
t.Errorf("expected: %v\ngot: %v", tagValue, got)
|
||||
}
|
||||
tracer.Add(1)
|
||||
tracer.Done()
|
||||
tracer.Wait()
|
||||
}
|
89
vendor/github.com/influxdata/influxdb/stress/v2/stress_client/util.go
generated
vendored
Normal file
89
vendor/github.com/influxdata/influxdb/stress/v2/stress_client/util.go
generated
vendored
Normal file
@@ -0,0 +1,89 @@
|
||||
package stressClient
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"fmt"
|
||||
"log"
|
||||
"strconv"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// ###########################################
|
||||
// ConcurrencyLimiter and associated methods #
|
||||
// ###########################################
|
||||
|
||||
// ConcurrencyLimiter ensures that no more than a specified
|
||||
// max number of goroutines are running.
|
||||
type ConcurrencyLimiter struct {
|
||||
inc chan chan struct{}
|
||||
dec chan struct{}
|
||||
max int
|
||||
count int
|
||||
|
||||
sync.Mutex
|
||||
}
|
||||
|
||||
// NewConcurrencyLimiter returns a configured limiter that will
|
||||
// ensure that calls to Increment will block if the max is hit.
|
||||
func NewConcurrencyLimiter(max int) *ConcurrencyLimiter {
|
||||
c := &ConcurrencyLimiter{
|
||||
inc: make(chan chan struct{}),
|
||||
dec: make(chan struct{}, max),
|
||||
max: max,
|
||||
}
|
||||
go c.handleLimits()
|
||||
return c
|
||||
}
|
||||
|
||||
// Increment will increase the count of running goroutines by 1.
|
||||
// if the number is currently at the max, the call to Increment
|
||||
// will block until another goroutine decrements.
|
||||
func (c *ConcurrencyLimiter) Increment() {
|
||||
r := make(chan struct{})
|
||||
c.inc <- r
|
||||
<-r
|
||||
}
|
||||
|
||||
// Decrement will reduce the count of running goroutines by 1
|
||||
func (c *ConcurrencyLimiter) Decrement() {
|
||||
c.dec <- struct{}{}
|
||||
}
|
||||
|
||||
// NewMax resets the max of a ConcurrencyLimiter.
|
||||
func (c *ConcurrencyLimiter) NewMax(i int) {
|
||||
c.Lock()
|
||||
defer c.Unlock()
|
||||
c.max = i
|
||||
}
|
||||
|
||||
// handleLimits runs in a goroutine to manage the count of
|
||||
// running goroutines.
|
||||
func (c *ConcurrencyLimiter) handleLimits() {
|
||||
for {
|
||||
r := <-c.inc
|
||||
c.Lock()
|
||||
if c.count >= c.max {
|
||||
<-c.dec
|
||||
c.count--
|
||||
}
|
||||
c.Unlock()
|
||||
c.count++
|
||||
r <- struct{}{}
|
||||
}
|
||||
}
|
||||
|
||||
// Utility interger parsing function
|
||||
func parseInt(s string) int {
|
||||
i, err := strconv.ParseInt(s, 10, 64)
|
||||
if err != nil {
|
||||
log.Fatalf("Error parsing integer:\n String: %v\n Error: %v\n", s, err)
|
||||
}
|
||||
return int(i)
|
||||
}
|
||||
|
||||
// Utility for making random strings of length n
|
||||
func randStr(n int) string {
|
||||
b := make([]byte, n/2)
|
||||
_, _ = rand.Read(b)
|
||||
return fmt.Sprintf("%x", b)
|
||||
}
|
Reference in New Issue
Block a user