You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@trafficcontrol.apache.org by ne...@apache.org on 2017/01/13 23:36:20 UTC
[24/29] incubator-trafficcontrol git commit: Update vendor going more
thoroughly through deps recursively... some cleanup may be called for in a
follow up PR
http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/4df63f3a/traffic_stats/vendor/github.com/influxdata/influxdb/client/v2/client_test.go
----------------------------------------------------------------------
diff --git a/traffic_stats/vendor/github.com/influxdata/influxdb/client/v2/client_test.go b/traffic_stats/vendor/github.com/influxdata/influxdb/client/v2/client_test.go
deleted file mode 100644
index d27c162..0000000
--- a/traffic_stats/vendor/github.com/influxdata/influxdb/client/v2/client_test.go
+++ /dev/null
@@ -1,525 +0,0 @@
-package client
-
-import (
- "encoding/json"
- "net/http"
- "net/http/httptest"
- "reflect"
- "strings"
- "sync"
- "testing"
- "time"
-)
-
-func TestUDPClient_Query(t *testing.T) {
- config := UDPConfig{Addr: "localhost:8089"}
- c, err := NewUDPClient(config)
- if err != nil {
- t.Errorf("unexpected error. expected %v, actual %v", nil, err)
- }
- defer c.Close()
- query := Query{}
- _, err = c.Query(query)
- if err == nil {
- t.Error("Querying UDP client should fail")
- }
-}
-
-func TestUDPClient_Ping(t *testing.T) {
- config := UDPConfig{Addr: "localhost:8089"}
- c, err := NewUDPClient(config)
- if err != nil {
- t.Errorf("unexpected error. expected %v, actual %v", nil, err)
- }
- defer c.Close()
-
- rtt, version, err := c.Ping(0)
- if rtt != 0 || version != "" || err != nil {
- t.Errorf("unexpected error. expected (%v, '%v', %v), actual (%v, '%v', %v)", 0, "", nil, rtt, version, err)
- }
-}
-
-func TestUDPClient_Write(t *testing.T) {
- config := UDPConfig{Addr: "localhost:8089"}
- c, err := NewUDPClient(config)
- if err != nil {
- t.Errorf("unexpected error. expected %v, actual %v", nil, err)
- }
- defer c.Close()
-
- bp, err := NewBatchPoints(BatchPointsConfig{})
- if err != nil {
- t.Errorf("unexpected error. expected %v, actual %v", nil, err)
- }
-
- fields := make(map[string]interface{})
- fields["value"] = 1.0
- pt, _ := NewPoint("cpu", make(map[string]string), fields)
- bp.AddPoint(pt)
-
- err = c.Write(bp)
- if err != nil {
- t.Errorf("unexpected error. expected %v, actual %v", nil, err)
- }
-}
-
-func TestUDPClient_BadAddr(t *testing.T) {
- config := UDPConfig{Addr: "foobar@wahoo"}
- c, err := NewUDPClient(config)
- if err == nil {
- defer c.Close()
- t.Error("Expected resolve error")
- }
-}
-
-func TestUDPClient_Batches(t *testing.T) {
- var logger writeLogger
- var cl udpclient
-
- cl.conn = &logger
- cl.payloadSize = 20 // should allow for two points per batch
-
- // expected point should look like this: "cpu a=1i"
- fields := map[string]interface{}{"a": 1}
-
- p, _ := NewPoint("cpu", nil, fields, time.Time{})
-
- bp, _ := NewBatchPoints(BatchPointsConfig{})
-
- for i := 0; i < 9; i++ {
- bp.AddPoint(p)
- }
-
- if err := cl.Write(bp); err != nil {
- t.Fatalf("Unexpected error during Write: %v", err)
- }
-
- if len(logger.writes) != 5 {
- t.Errorf("Mismatched write count: got %v, exp %v", len(logger.writes), 5)
- }
-}
-
-func TestUDPClient_Split(t *testing.T) {
- var logger writeLogger
- var cl udpclient
-
- cl.conn = &logger
- cl.payloadSize = 1 // force one field per point
-
- fields := map[string]interface{}{"a": 1, "b": 2, "c": 3, "d": 4}
-
- p, _ := NewPoint("cpu", nil, fields, time.Unix(1, 0))
-
- bp, _ := NewBatchPoints(BatchPointsConfig{})
-
- bp.AddPoint(p)
-
- if err := cl.Write(bp); err != nil {
- t.Fatalf("Unexpected error during Write: %v", err)
- }
-
- if len(logger.writes) != len(fields) {
- t.Errorf("Mismatched write count: got %v, exp %v", len(logger.writes), len(fields))
- }
-}
-
-type writeLogger struct {
- writes [][]byte
-}
-
-func (w *writeLogger) Write(b []byte) (int, error) {
- w.writes = append(w.writes, append([]byte(nil), b...))
- return len(b), nil
-}
-
-func (w *writeLogger) Close() error { return nil }
-
-func TestClient_Query(t *testing.T) {
- ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
- var data Response
- w.WriteHeader(http.StatusOK)
- _ = json.NewEncoder(w).Encode(data)
- }))
- defer ts.Close()
-
- config := HTTPConfig{Addr: ts.URL}
- c, _ := NewHTTPClient(config)
- defer c.Close()
-
- query := Query{}
- _, err := c.Query(query)
- if err != nil {
- t.Errorf("unexpected error. expected %v, actual %v", nil, err)
- }
-}
-
-func TestClient_BoundParameters(t *testing.T) {
- var parameterString string
- ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
- var data Response
- r.ParseForm()
- parameterString = r.FormValue("params")
- w.WriteHeader(http.StatusOK)
- _ = json.NewEncoder(w).Encode(data)
- }))
- defer ts.Close()
-
- config := HTTPConfig{Addr: ts.URL}
- c, _ := NewHTTPClient(config)
- defer c.Close()
-
- expectedParameters := map[string]interface{}{
- "testStringParameter": "testStringValue",
- "testNumberParameter": 12.3,
- }
-
- query := Query{
- Parameters: expectedParameters,
- }
-
- _, err := c.Query(query)
- if err != nil {
- t.Errorf("unexpected error. expected %v, actual %v", nil, err)
- }
-
- var actualParameters map[string]interface{}
-
- err = json.Unmarshal([]byte(parameterString), &actualParameters)
- if err != nil {
- t.Errorf("unexpected error. expected %v, actual %v", nil, err)
- }
-
- if !reflect.DeepEqual(expectedParameters, actualParameters) {
- t.Errorf("unexpected parameters. expected %v, actual %v", expectedParameters, actualParameters)
- }
-}
-
-func TestClient_BasicAuth(t *testing.T) {
- ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
- u, p, ok := r.BasicAuth()
-
- if !ok {
- t.Errorf("basic auth error")
- }
- if u != "username" {
- t.Errorf("unexpected username, expected %q, actual %q", "username", u)
- }
- if p != "password" {
- t.Errorf("unexpected password, expected %q, actual %q", "password", p)
- }
- var data Response
- w.WriteHeader(http.StatusOK)
- _ = json.NewEncoder(w).Encode(data)
- }))
- defer ts.Close()
-
- config := HTTPConfig{Addr: ts.URL, Username: "username", Password: "password"}
- c, _ := NewHTTPClient(config)
- defer c.Close()
-
- query := Query{}
- _, err := c.Query(query)
- if err != nil {
- t.Errorf("unexpected error. expected %v, actual %v", nil, err)
- }
-}
-
-func TestClient_Ping(t *testing.T) {
- ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
- var data Response
- w.WriteHeader(http.StatusNoContent)
- _ = json.NewEncoder(w).Encode(data)
- }))
- defer ts.Close()
-
- config := HTTPConfig{Addr: ts.URL}
- c, _ := NewHTTPClient(config)
- defer c.Close()
-
- _, _, err := c.Ping(0)
- if err != nil {
- t.Errorf("unexpected error. expected %v, actual %v", nil, err)
- }
-}
-
-func TestClient_Concurrent_Use(t *testing.T) {
- ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
- w.WriteHeader(http.StatusOK)
- w.Write([]byte(`{}`))
- }))
- defer ts.Close()
-
- config := HTTPConfig{Addr: ts.URL}
- c, _ := NewHTTPClient(config)
- defer c.Close()
-
- var wg sync.WaitGroup
- wg.Add(3)
- n := 1000
-
- go func() {
- defer wg.Done()
- bp, err := NewBatchPoints(BatchPointsConfig{})
- if err != nil {
- t.Errorf("got error %v", err)
- }
-
- for i := 0; i < n; i++ {
- if err = c.Write(bp); err != nil {
- t.Fatalf("got error %v", err)
- }
- }
- }()
-
- go func() {
- defer wg.Done()
- var q Query
- for i := 0; i < n; i++ {
- if _, err := c.Query(q); err != nil {
- t.Fatalf("got error %v", err)
- }
- }
- }()
-
- go func() {
- defer wg.Done()
- for i := 0; i < n; i++ {
- c.Ping(time.Second)
- }
- }()
- wg.Wait()
-}
-
-func TestClient_Write(t *testing.T) {
- ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
- var data Response
- w.WriteHeader(http.StatusNoContent)
- _ = json.NewEncoder(w).Encode(data)
- }))
- defer ts.Close()
-
- config := HTTPConfig{Addr: ts.URL}
- c, _ := NewHTTPClient(config)
- defer c.Close()
-
- bp, err := NewBatchPoints(BatchPointsConfig{})
- if err != nil {
- t.Errorf("unexpected error. expected %v, actual %v", nil, err)
- }
- err = c.Write(bp)
- if err != nil {
- t.Errorf("unexpected error. expected %v, actual %v", nil, err)
- }
-}
-
-func TestClient_UserAgent(t *testing.T) {
- receivedUserAgent := ""
- ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
- receivedUserAgent = r.UserAgent()
-
- var data Response
- w.WriteHeader(http.StatusOK)
- _ = json.NewEncoder(w).Encode(data)
- }))
- defer ts.Close()
-
- _, err := http.Get(ts.URL)
- if err != nil {
- t.Errorf("unexpected error. expected %v, actual %v", nil, err)
- }
-
- tests := []struct {
- name string
- userAgent string
- expected string
- }{
- {
- name: "Empty user agent",
- userAgent: "",
- expected: "InfluxDBClient",
- },
- {
- name: "Custom user agent",
- userAgent: "Test Influx Client",
- expected: "Test Influx Client",
- },
- }
-
- for _, test := range tests {
-
- config := HTTPConfig{Addr: ts.URL, UserAgent: test.userAgent}
- c, _ := NewHTTPClient(config)
- defer c.Close()
-
- receivedUserAgent = ""
- query := Query{}
- _, err = c.Query(query)
- if err != nil {
- t.Errorf("unexpected error. expected %v, actual %v", nil, err)
- }
- if !strings.HasPrefix(receivedUserAgent, test.expected) {
- t.Errorf("Unexpected user agent. expected %v, actual %v", test.expected, receivedUserAgent)
- }
-
- receivedUserAgent = ""
- bp, _ := NewBatchPoints(BatchPointsConfig{})
- err = c.Write(bp)
- if err != nil {
- t.Errorf("unexpected error. expected %v, actual %v", nil, err)
- }
- if !strings.HasPrefix(receivedUserAgent, test.expected) {
- t.Errorf("Unexpected user agent. expected %v, actual %v", test.expected, receivedUserAgent)
- }
-
- receivedUserAgent = ""
- _, err := c.Query(query)
- if err != nil {
- t.Errorf("unexpected error. expected %v, actual %v", nil, err)
- }
- if receivedUserAgent != test.expected {
- t.Errorf("Unexpected user agent. expected %v, actual %v", test.expected, receivedUserAgent)
- }
- }
-}
-
-func TestClient_PointString(t *testing.T) {
- const shortForm = "2006-Jan-02"
- time1, _ := time.Parse(shortForm, "2013-Feb-03")
- tags := map[string]string{"cpu": "cpu-total"}
- fields := map[string]interface{}{"idle": 10.1, "system": 50.9, "user": 39.0}
- p, _ := NewPoint("cpu_usage", tags, fields, time1)
-
- s := "cpu_usage,cpu=cpu-total idle=10.1,system=50.9,user=39 1359849600000000000"
- if p.String() != s {
- t.Errorf("Point String Error, got %s, expected %s", p.String(), s)
- }
-
- s = "cpu_usage,cpu=cpu-total idle=10.1,system=50.9,user=39 1359849600000"
- if p.PrecisionString("ms") != s {
- t.Errorf("Point String Error, got %s, expected %s",
- p.PrecisionString("ms"), s)
- }
-}
-
-func TestClient_PointWithoutTimeString(t *testing.T) {
- tags := map[string]string{"cpu": "cpu-total"}
- fields := map[string]interface{}{"idle": 10.1, "system": 50.9, "user": 39.0}
- p, _ := NewPoint("cpu_usage", tags, fields)
-
- s := "cpu_usage,cpu=cpu-total idle=10.1,system=50.9,user=39"
- if p.String() != s {
- t.Errorf("Point String Error, got %s, expected %s", p.String(), s)
- }
-
- if p.PrecisionString("ms") != s {
- t.Errorf("Point String Error, got %s, expected %s",
- p.PrecisionString("ms"), s)
- }
-}
-
-func TestClient_PointName(t *testing.T) {
- tags := map[string]string{"cpu": "cpu-total"}
- fields := map[string]interface{}{"idle": 10.1, "system": 50.9, "user": 39.0}
- p, _ := NewPoint("cpu_usage", tags, fields)
-
- exp := "cpu_usage"
- if p.Name() != exp {
- t.Errorf("Error, got %s, expected %s",
- p.Name(), exp)
- }
-}
-
-func TestClient_PointTags(t *testing.T) {
- tags := map[string]string{"cpu": "cpu-total"}
- fields := map[string]interface{}{"idle": 10.1, "system": 50.9, "user": 39.0}
- p, _ := NewPoint("cpu_usage", tags, fields)
-
- if !reflect.DeepEqual(tags, p.Tags()) {
- t.Errorf("Error, got %v, expected %v",
- p.Tags(), tags)
- }
-}
-
-func TestClient_PointUnixNano(t *testing.T) {
- const shortForm = "2006-Jan-02"
- time1, _ := time.Parse(shortForm, "2013-Feb-03")
- tags := map[string]string{"cpu": "cpu-total"}
- fields := map[string]interface{}{"idle": 10.1, "system": 50.9, "user": 39.0}
- p, _ := NewPoint("cpu_usage", tags, fields, time1)
-
- exp := int64(1359849600000000000)
- if p.UnixNano() != exp {
- t.Errorf("Error, got %d, expected %d",
- p.UnixNano(), exp)
- }
-}
-
-func TestClient_PointFields(t *testing.T) {
- tags := map[string]string{"cpu": "cpu-total"}
- fields := map[string]interface{}{"idle": 10.1, "system": 50.9, "user": 39.0}
- p, _ := NewPoint("cpu_usage", tags, fields)
-
- pfields, err := p.Fields()
- if err != nil {
- t.Fatal(err)
- }
- if !reflect.DeepEqual(fields, pfields) {
- t.Errorf("Error, got %v, expected %v",
- pfields, fields)
- }
-}
-
-func TestBatchPoints_PrecisionError(t *testing.T) {
- _, err := NewBatchPoints(BatchPointsConfig{Precision: "foobar"})
- if err == nil {
- t.Errorf("Precision: foobar should have errored")
- }
-
- bp, _ := NewBatchPoints(BatchPointsConfig{Precision: "ns"})
- err = bp.SetPrecision("foobar")
- if err == nil {
- t.Errorf("Precision: foobar should have errored")
- }
-}
-
-func TestBatchPoints_SettersGetters(t *testing.T) {
- bp, _ := NewBatchPoints(BatchPointsConfig{
- Precision: "ns",
- Database: "db",
- RetentionPolicy: "rp",
- WriteConsistency: "wc",
- })
- if bp.Precision() != "ns" {
- t.Errorf("Expected: %s, got %s", bp.Precision(), "ns")
- }
- if bp.Database() != "db" {
- t.Errorf("Expected: %s, got %s", bp.Database(), "db")
- }
- if bp.RetentionPolicy() != "rp" {
- t.Errorf("Expected: %s, got %s", bp.RetentionPolicy(), "rp")
- }
- if bp.WriteConsistency() != "wc" {
- t.Errorf("Expected: %s, got %s", bp.WriteConsistency(), "wc")
- }
-
- bp.SetDatabase("db2")
- bp.SetRetentionPolicy("rp2")
- bp.SetWriteConsistency("wc2")
- err := bp.SetPrecision("s")
- if err != nil {
- t.Errorf("Did not expect error: %s", err.Error())
- }
-
- if bp.Precision() != "s" {
- t.Errorf("Expected: %s, got %s", bp.Precision(), "s")
- }
- if bp.Database() != "db2" {
- t.Errorf("Expected: %s, got %s", bp.Database(), "db2")
- }
- if bp.RetentionPolicy() != "rp2" {
- t.Errorf("Expected: %s, got %s", bp.RetentionPolicy(), "rp2")
- }
- if bp.WriteConsistency() != "wc2" {
- t.Errorf("Expected: %s, got %s", bp.WriteConsistency(), "wc2")
- }
-}
http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/4df63f3a/traffic_stats/vendor/github.com/influxdata/influxdb/client/v2/example_test.go
----------------------------------------------------------------------
diff --git a/traffic_stats/vendor/github.com/influxdata/influxdb/client/v2/example_test.go b/traffic_stats/vendor/github.com/influxdata/influxdb/client/v2/example_test.go
deleted file mode 100644
index 68bb24b..0000000
--- a/traffic_stats/vendor/github.com/influxdata/influxdb/client/v2/example_test.go
+++ /dev/null
@@ -1,265 +0,0 @@
-package client_test
-
-import (
- "fmt"
- "math/rand"
- "os"
- "time"
-
- "github.com/influxdata/influxdb/client/v2"
-)
-
-// Create a new client
-func ExampleClient() {
- // NOTE: this assumes you've setup a user and have setup shell env variables,
- // namely INFLUX_USER/INFLUX_PWD. If not just omit Username/Password below.
- _, err := client.NewHTTPClient(client.HTTPConfig{
- Addr: "http://localhost:8086",
- Username: os.Getenv("INFLUX_USER"),
- Password: os.Getenv("INFLUX_PWD"),
- })
- if err != nil {
- fmt.Println("Error creating InfluxDB Client: ", err.Error())
- }
-}
-
-// Write a point using the UDP client
-func ExampleClient_uDP() {
- // Make client
- config := client.UDPConfig{Addr: "localhost:8089"}
- c, err := client.NewUDPClient(config)
- if err != nil {
- fmt.Println("Error: ", err.Error())
- }
- defer c.Close()
-
- // Create a new point batch
- bp, _ := client.NewBatchPoints(client.BatchPointsConfig{
- Precision: "s",
- })
-
- // Create a point and add to batch
- tags := map[string]string{"cpu": "cpu-total"}
- fields := map[string]interface{}{
- "idle": 10.1,
- "system": 53.3,
- "user": 46.6,
- }
- pt, err := client.NewPoint("cpu_usage", tags, fields, time.Now())
- if err != nil {
- fmt.Println("Error: ", err.Error())
- }
- bp.AddPoint(pt)
-
- // Write the batch
- c.Write(bp)
-}
-
-// Ping the cluster using the HTTP client
-func ExampleClient_Ping() {
- // Make client
- c, err := client.NewHTTPClient(client.HTTPConfig{
- Addr: "http://localhost:8086",
- })
- if err != nil {
- fmt.Println("Error creating InfluxDB Client: ", err.Error())
- }
- defer c.Close()
-
- _, _, err = c.Ping(0)
- if err != nil {
- fmt.Println("Error pinging InfluxDB Cluster: ", err.Error())
- }
-}
-
-// Write a point using the HTTP client
-func ExampleClient_write() {
- // Make client
- c, err := client.NewHTTPClient(client.HTTPConfig{
- Addr: "http://localhost:8086",
- })
- if err != nil {
- fmt.Println("Error creating InfluxDB Client: ", err.Error())
- }
- defer c.Close()
-
- // Create a new point batch
- bp, _ := client.NewBatchPoints(client.BatchPointsConfig{
- Database: "BumbleBeeTuna",
- Precision: "s",
- })
-
- // Create a point and add to batch
- tags := map[string]string{"cpu": "cpu-total"}
- fields := map[string]interface{}{
- "idle": 10.1,
- "system": 53.3,
- "user": 46.6,
- }
- pt, err := client.NewPoint("cpu_usage", tags, fields, time.Now())
- if err != nil {
- fmt.Println("Error: ", err.Error())
- }
- bp.AddPoint(pt)
-
- // Write the batch
- c.Write(bp)
-}
-
-// Create a batch and add a point
-func ExampleBatchPoints() {
- // Create a new point batch
- bp, _ := client.NewBatchPoints(client.BatchPointsConfig{
- Database: "BumbleBeeTuna",
- Precision: "s",
- })
-
- // Create a point and add to batch
- tags := map[string]string{"cpu": "cpu-total"}
- fields := map[string]interface{}{
- "idle": 10.1,
- "system": 53.3,
- "user": 46.6,
- }
- pt, err := client.NewPoint("cpu_usage", tags, fields, time.Now())
- if err != nil {
- fmt.Println("Error: ", err.Error())
- }
- bp.AddPoint(pt)
-}
-
-// Using the BatchPoints setter functions
-func ExampleBatchPoints_setters() {
- // Create a new point batch
- bp, _ := client.NewBatchPoints(client.BatchPointsConfig{})
- bp.SetDatabase("BumbleBeeTuna")
- bp.SetPrecision("ms")
-
- // Create a point and add to batch
- tags := map[string]string{"cpu": "cpu-total"}
- fields := map[string]interface{}{
- "idle": 10.1,
- "system": 53.3,
- "user": 46.6,
- }
- pt, err := client.NewPoint("cpu_usage", tags, fields, time.Now())
- if err != nil {
- fmt.Println("Error: ", err.Error())
- }
- bp.AddPoint(pt)
-}
-
-// Create a new point with a timestamp
-func ExamplePoint() {
- tags := map[string]string{"cpu": "cpu-total"}
- fields := map[string]interface{}{
- "idle": 10.1,
- "system": 53.3,
- "user": 46.6,
- }
- pt, err := client.NewPoint("cpu_usage", tags, fields, time.Now())
- if err == nil {
- fmt.Println("We created a point: ", pt.String())
- }
-}
-
-// Create a new point without a timestamp
-func ExamplePoint_withoutTime() {
- tags := map[string]string{"cpu": "cpu-total"}
- fields := map[string]interface{}{
- "idle": 10.1,
- "system": 53.3,
- "user": 46.6,
- }
- pt, err := client.NewPoint("cpu_usage", tags, fields)
- if err == nil {
- fmt.Println("We created a point w/o time: ", pt.String())
- }
-}
-
-// Write 1000 points
-func ExampleClient_write1000() {
- sampleSize := 1000
-
- // Make client
- c, err := client.NewHTTPClient(client.HTTPConfig{
- Addr: "http://localhost:8086",
- })
- if err != nil {
- fmt.Println("Error creating InfluxDB Client: ", err.Error())
- }
- defer c.Close()
-
- rand.Seed(42)
-
- bp, _ := client.NewBatchPoints(client.BatchPointsConfig{
- Database: "systemstats",
- Precision: "us",
- })
-
- for i := 0; i < sampleSize; i++ {
- regions := []string{"us-west1", "us-west2", "us-west3", "us-east1"}
- tags := map[string]string{
- "cpu": "cpu-total",
- "host": fmt.Sprintf("host%d", rand.Intn(1000)),
- "region": regions[rand.Intn(len(regions))],
- }
-
- idle := rand.Float64() * 100.0
- fields := map[string]interface{}{
- "idle": idle,
- "busy": 100.0 - idle,
- }
-
- pt, err := client.NewPoint(
- "cpu_usage",
- tags,
- fields,
- time.Now(),
- )
- if err != nil {
- println("Error:", err.Error())
- continue
- }
- bp.AddPoint(pt)
- }
-
- err = c.Write(bp)
- if err != nil {
- fmt.Println("Error: ", err.Error())
- }
-}
-
-// Make a Query
-func ExampleClient_query() {
- // Make client
- c, err := client.NewHTTPClient(client.HTTPConfig{
- Addr: "http://localhost:8086",
- })
- if err != nil {
- fmt.Println("Error creating InfluxDB Client: ", err.Error())
- }
- defer c.Close()
-
- q := client.NewQuery("SELECT count(value) FROM shapes", "square_holes", "ns")
- if response, err := c.Query(q); err == nil && response.Error() == nil {
- fmt.Println(response.Results)
- }
-}
-
-// Create a Database with a query
-func ExampleClient_createDatabase() {
- // Make client
- c, err := client.NewHTTPClient(client.HTTPConfig{
- Addr: "http://localhost:8086",
- })
- if err != nil {
- fmt.Println("Error creating InfluxDB Client: ", err.Error())
- }
- defer c.Close()
-
- q := client.NewQuery("CREATE DATABASE telegraf", "", "")
- if response, err := c.Query(q); err == nil && response.Error() == nil {
- fmt.Println(response.Results)
- }
-}
http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/4df63f3a/traffic_stats/vendor/github.com/influxdata/influxdb/models/consistency.go
----------------------------------------------------------------------
diff --git a/traffic_stats/vendor/github.com/influxdata/influxdb/models/consistency.go b/traffic_stats/vendor/github.com/influxdata/influxdb/models/consistency.go
new file mode 100644
index 0000000..2a3269b
--- /dev/null
+++ b/traffic_stats/vendor/github.com/influxdata/influxdb/models/consistency.go
@@ -0,0 +1,48 @@
+package models
+
+import (
+ "errors"
+ "strings"
+)
+
+// ConsistencyLevel represent a required replication criteria before a write can
+// be returned as successful.
+//
+// The consistency level is handled in open-source InfluxDB but only applicable to clusters.
+type ConsistencyLevel int
+
+const (
+ // ConsistencyLevelAny allows for hinted handoff, potentially no write happened yet.
+ ConsistencyLevelAny ConsistencyLevel = iota
+
+ // ConsistencyLevelOne requires at least one data node acknowledged a write.
+ ConsistencyLevelOne
+
+ // ConsistencyLevelQuorum requires a quorum of data nodes to acknowledge a write.
+ ConsistencyLevelQuorum
+
+ // ConsistencyLevelAll requires all data nodes to acknowledge a write.
+ ConsistencyLevelAll
+)
+
+var (
+ // ErrInvalidConsistencyLevel is returned when parsing the string version
+ // of a consistency level.
+ ErrInvalidConsistencyLevel = errors.New("invalid consistency level")
+)
+
+// ParseConsistencyLevel converts a consistency level string to the corresponding ConsistencyLevel const.
+func ParseConsistencyLevel(level string) (ConsistencyLevel, error) {
+ switch strings.ToLower(level) {
+ case "any":
+ return ConsistencyLevelAny, nil
+ case "one":
+ return ConsistencyLevelOne, nil
+ case "quorum":
+ return ConsistencyLevelQuorum, nil
+ case "all":
+ return ConsistencyLevelAll, nil
+ default:
+ return 0, ErrInvalidConsistencyLevel
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/4df63f3a/traffic_stats/vendor/github.com/influxdata/influxdb/models/inline_fnv.go
----------------------------------------------------------------------
diff --git a/traffic_stats/vendor/github.com/influxdata/influxdb/models/inline_fnv.go b/traffic_stats/vendor/github.com/influxdata/influxdb/models/inline_fnv.go
new file mode 100644
index 0000000..1d8ae29
--- /dev/null
+++ b/traffic_stats/vendor/github.com/influxdata/influxdb/models/inline_fnv.go
@@ -0,0 +1,32 @@
+package models
+
+// from stdlib hash/fnv/fnv.go
+const (
+ prime64 = 1099511628211
+ offset64 = 14695981039346656037
+)
+
+// InlineFNV64a is an alloc-free port of the standard library's fnv64a.
+// See https://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function.
+type InlineFNV64a uint64
+
+// NewInlineFNV64a returns a new instance of InlineFNV64a.
+func NewInlineFNV64a() InlineFNV64a {
+ return offset64
+}
+
+// Write adds data to the running hash.
+func (s *InlineFNV64a) Write(data []byte) (int, error) {
+ hash := uint64(*s)
+ for _, c := range data {
+ hash ^= uint64(c)
+ hash *= prime64
+ }
+ *s = InlineFNV64a(hash)
+ return len(data), nil
+}
+
+// Sum64 returns the uint64 of the current resulting hash.
+func (s *InlineFNV64a) Sum64() uint64 {
+ return uint64(*s)
+}
http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/4df63f3a/traffic_stats/vendor/github.com/influxdata/influxdb/models/inline_strconv_parse.go
----------------------------------------------------------------------
diff --git a/traffic_stats/vendor/github.com/influxdata/influxdb/models/inline_strconv_parse.go b/traffic_stats/vendor/github.com/influxdata/influxdb/models/inline_strconv_parse.go
new file mode 100644
index 0000000..727ce35
--- /dev/null
+++ b/traffic_stats/vendor/github.com/influxdata/influxdb/models/inline_strconv_parse.go
@@ -0,0 +1,38 @@
+package models
+
+import (
+ "reflect"
+ "strconv"
+ "unsafe"
+)
+
+// parseIntBytes is a zero-alloc wrapper around strconv.ParseInt.
+func parseIntBytes(b []byte, base int, bitSize int) (i int64, err error) {
+ s := unsafeBytesToString(b)
+ return strconv.ParseInt(s, base, bitSize)
+}
+
+// parseFloatBytes is a zero-alloc wrapper around strconv.ParseFloat.
+func parseFloatBytes(b []byte, bitSize int) (float64, error) {
+ s := unsafeBytesToString(b)
+ return strconv.ParseFloat(s, bitSize)
+}
+
+// parseBoolBytes is a zero-alloc wrapper around strconv.ParseBool.
+func parseBoolBytes(b []byte) (bool, error) {
+ return strconv.ParseBool(unsafeBytesToString(b))
+}
+
+// unsafeBytesToString converts a []byte to a string without a heap allocation.
+//
+// It is unsafe, and is intended to prepare input to short-lived functions
+// that require strings.
+func unsafeBytesToString(in []byte) string {
+ src := *(*reflect.SliceHeader)(unsafe.Pointer(&in))
+ dst := reflect.StringHeader{
+ Data: src.Data,
+ Len: src.Len,
+ }
+ s := *(*string)(unsafe.Pointer(&dst))
+ return s
+}
http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/4df63f3a/traffic_stats/vendor/github.com/influxdata/influxdb/models/points.go
----------------------------------------------------------------------
diff --git a/traffic_stats/vendor/github.com/influxdata/influxdb/models/points.go b/traffic_stats/vendor/github.com/influxdata/influxdb/models/points.go
new file mode 100644
index 0000000..f415e01
--- /dev/null
+++ b/traffic_stats/vendor/github.com/influxdata/influxdb/models/points.go
@@ -0,0 +1,1997 @@
+// Package models implements basic objects used throughout the TICK stack.
+package models
+
+import (
+ "bytes"
+ "encoding/binary"
+ "errors"
+ "fmt"
+ "math"
+ "sort"
+ "strconv"
+ "strings"
+ "time"
+
+ "github.com/influxdata/influxdb/pkg/escape"
+)
+
+var (
+ measurementEscapeCodes = map[byte][]byte{
+ ',': []byte(`\,`),
+ ' ': []byte(`\ `),
+ }
+
+ tagEscapeCodes = map[byte][]byte{
+ ',': []byte(`\,`),
+ ' ': []byte(`\ `),
+ '=': []byte(`\=`),
+ }
+
+ // ErrPointMustHaveAField is returned when operating on a point that does not have any fields.
+ ErrPointMustHaveAField = errors.New("point without fields is unsupported")
+
+ // ErrInvalidNumber is returned when a number is expected but not provided.
+ ErrInvalidNumber = errors.New("invalid number")
+
+ // ErrInvalidPoint is returned when a point cannot be parsed correctly.
+ ErrInvalidPoint = errors.New("point is invalid")
+)
+
+const (
+ // MaxKeyLength is the largest allowed size of the combined measurement and tag keys.
+ MaxKeyLength = 65535
+)
+
+// Point defines the values that will be written to the database.
+type Point interface {
+ // Name return the measurement name for the point.
+ Name() string
+
+ // SetName updates the measurement name for the point.
+ SetName(string)
+
+ // Tags returns the tag set for the point.
+ Tags() Tags
+
+ // AddTag adds or replaces a tag value for a point.
+ AddTag(key, value string)
+
+ // SetTags replaces the tags for the point.
+ SetTags(tags Tags)
+
+ // Fields returns the fields for the point.
+ Fields() (Fields, error)
+
+ // Time return the timestamp for the point.
+ Time() time.Time
+
+ // SetTime updates the timestamp for the point.
+ SetTime(t time.Time)
+
+ // UnixNano returns the timestamp of the point as nanoseconds since Unix epoch.
+ UnixNano() int64
+
+ // HashID returns a non-cryptographic checksum of the point's key.
+ HashID() uint64
+
+ // Key returns the key (measurement joined with tags) of the point.
+ Key() []byte
+
+ // String returns a string representation of the point. If there is a
+ // timestamp associated with the point then it will be specified with the default
+ // precision of nanoseconds.
+ String() string
+
+ // MarshalBinary returns a binary representation of the point.
+ MarshalBinary() ([]byte, error)
+
+ // PrecisionString returns a string representation of the point. If there
+ // is a timestamp associated with the point then it will be specified in the
+ // given unit.
+ PrecisionString(precision string) string
+
+ // RoundedString returns a string representation of the point. If there
+ // is a timestamp associated with the point, then it will be rounded to the
+ // given duration.
+ RoundedString(d time.Duration) string
+
+ // Split will attempt to return multiple points with the same timestamp whose
+ // string representations are no longer than size. Points with a single field or
+ // a point without a timestamp may exceed the requested size.
+ Split(size int) []Point
+
+ // Round will round the timestamp of the point to the given duration.
+ Round(d time.Duration)
+
+ // StringSize returns the length of the string that would be returned by String().
+ StringSize() int
+
+ // AppendString appends the result of String() to the provided buffer and returns
+ // the result, potentially reducing string allocations.
+ AppendString(buf []byte) []byte
+
+ // FieldIterator retuns a FieldIterator that can be used to traverse the
+ // fields of a point without constructing the in-memory map.
+ FieldIterator() FieldIterator
+}
+
+// FieldType represents the type of a field.
+type FieldType int
+
+const (
+ // Integer indicates the field's type is integer.
+ Integer FieldType = iota
+
+ // Float indicates the field's type is float.
+ Float
+
+ // Boolean indicates the field's type is boolean.
+ Boolean
+
+ // String indicates the field's type is string.
+ String
+
+ // Empty is used to indicate that there is no field.
+ Empty
+)
+
+// FieldIterator provides a low-allocation interface to iterate through a point's fields.
+type FieldIterator interface {
+ // Next indicates whether there any fields remaining.
+ Next() bool
+
+ // FieldKey returns the key of the current field.
+ FieldKey() []byte
+
+ // Type returns the FieldType of the current field.
+ Type() FieldType
+
+ // StringValue returns the string value of the current field.
+ StringValue() string
+
+ // IntegerValue returns the integer value of the current field.
+ IntegerValue() (int64, error)
+
+ // BooleanValue returns the boolean value of the current field.
+ BooleanValue() (bool, error)
+
+ // FloatValue returns the float value of the current field.
+ FloatValue() (float64, error)
+
+ // Delete deletes the current field.
+ Delete()
+
+ // Reset resets the iterator to its initial state.
+ Reset()
+}
+
+// Points represents a sortable list of points by timestamp.
+type Points []Point
+
+// Len implements sort.Interface.
+func (a Points) Len() int { return len(a) }
+
+// Less implements sort.Interface.
+func (a Points) Less(i, j int) bool { return a[i].Time().Before(a[j].Time()) }
+
+// Swap implements sort.Interface.
+func (a Points) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
+
+// point is the default implementation of Point.
+type point struct {
+ time time.Time
+
+ // text encoding of measurement and tags
+ // key must always be stored sorted by tags, if the original line was not sorted,
+ // we need to resort it
+ key []byte
+
+ // text encoding of field data
+ fields []byte
+
+ // text encoding of timestamp
+ ts []byte
+
+ // cached version of parsed fields from data
+ cachedFields map[string]interface{}
+
+ // cached version of parsed name from key
+ cachedName string
+
+ // cached version of parsed tags
+ cachedTags Tags
+
+ it fieldIterator
+}
+
+const (
+ // the number of characters for the largest possible int64 (9223372036854775807)
+ maxInt64Digits = 19
+
+ // the number of characters for the smallest possible int64 (-9223372036854775808)
+ minInt64Digits = 20
+
+ // the number of characters required for the largest float64 before a range check
+ // would occur during parsing
+ maxFloat64Digits = 25
+
+ // the number of characters required for smallest float64 before a range check occur
+ // would occur during parsing
+ minFloat64Digits = 27
+)
+
+// ParsePoints returns a slice of Points from a text representation of a point
+// with each point separated by newlines. If any points fail to parse, a non-nil error
+// will be returned in addition to the points that parsed successfully.
+func ParsePoints(buf []byte) ([]Point, error) {
+ return ParsePointsWithPrecision(buf, time.Now().UTC(), "n")
+}
+
+// ParsePointsString is identical to ParsePoints but accepts a string.
+func ParsePointsString(buf string) ([]Point, error) {
+ return ParsePoints([]byte(buf))
+}
+
+// ParseKey returns the measurement name and tags from a point.
+func ParseKey(buf []byte) (string, Tags, error) {
+ // Ignore the error because scanMeasurement returns "missing fields" which we ignore
+ // when just parsing a key
+ state, i, _ := scanMeasurement(buf, 0)
+
+ var tags Tags
+ if state == tagKeyState {
+ tags = parseTags(buf)
+ // scanMeasurement returns the location of the comma if there are tags, strip that off
+ return string(buf[:i-1]), tags, nil
+ }
+ return string(buf[:i]), tags, nil
+}
+
+// ParsePointsWithPrecision is similar to ParsePoints, but allows the
+// caller to provide a precision for time.
+func ParsePointsWithPrecision(buf []byte, defaultTime time.Time, precision string) ([]Point, error) {
+ points := make([]Point, 0, bytes.Count(buf, []byte{'\n'})+1)
+ var (
+ pos int
+ block []byte
+ failed []string
+ )
+ for pos < len(buf) {
+ pos, block = scanLine(buf, pos)
+ pos++
+
+ if len(block) == 0 {
+ continue
+ }
+
+ // lines which start with '#' are comments
+ start := skipWhitespace(block, 0)
+
+ // If line is all whitespace, just skip it
+ if start >= len(block) {
+ continue
+ }
+
+ if block[start] == '#' {
+ continue
+ }
+
+ // strip the newline if one is present
+ if block[len(block)-1] == '\n' {
+ block = block[:len(block)-1]
+ }
+
+ pt, err := parsePoint(block[start:], defaultTime, precision)
+ if err != nil {
+ failed = append(failed, fmt.Sprintf("unable to parse '%s': %v", string(block[start:len(block)]), err))
+ } else {
+ points = append(points, pt)
+ }
+
+ }
+ if len(failed) > 0 {
+ return points, fmt.Errorf("%s", strings.Join(failed, "\n"))
+ }
+ return points, nil
+
+}
+
+func parsePoint(buf []byte, defaultTime time.Time, precision string) (Point, error) {
+ // scan the first block which is measurement[,tag1=value1,tag2=value=2...]
+ pos, key, err := scanKey(buf, 0)
+ if err != nil {
+ return nil, err
+ }
+
+ // measurement name is required
+ if len(key) == 0 {
+ return nil, fmt.Errorf("missing measurement")
+ }
+
+ if len(key) > MaxKeyLength {
+ return nil, fmt.Errorf("max key length exceeded: %v > %v", len(key), MaxKeyLength)
+ }
+
+ // scan the second block is which is field1=value1[,field2=value2,...]
+ pos, fields, err := scanFields(buf, pos)
+ if err != nil {
+ return nil, err
+ }
+
+ // at least one field is required
+ if len(fields) == 0 {
+ return nil, fmt.Errorf("missing fields")
+ }
+
+ // scan the last block which is an optional integer timestamp
+ pos, ts, err := scanTime(buf, pos)
+ if err != nil {
+ return nil, err
+ }
+
+ pt := &point{
+ key: key,
+ fields: fields,
+ ts: ts,
+ }
+
+ if len(ts) == 0 {
+ pt.time = defaultTime
+ pt.SetPrecision(precision)
+ } else {
+ ts, err := parseIntBytes(ts, 10, 64)
+ if err != nil {
+ return nil, err
+ }
+ pt.time, err = SafeCalcTime(ts, precision)
+ if err != nil {
+ return nil, err
+ }
+
+ // Determine if there are illegal non-whitespace characters after the
+ // timestamp block.
+ for pos < len(buf) {
+ if buf[pos] != ' ' {
+ return nil, ErrInvalidPoint
+ }
+ pos++
+ }
+ }
+ return pt, nil
+}
+
+// GetPrecisionMultiplier will return a multiplier for the precision specified.
+func GetPrecisionMultiplier(precision string) int64 {
+ d := time.Nanosecond
+ switch precision {
+ case "u":
+ d = time.Microsecond
+ case "ms":
+ d = time.Millisecond
+ case "s":
+ d = time.Second
+ case "m":
+ d = time.Minute
+ case "h":
+ d = time.Hour
+ }
+ return int64(d)
+}
+
+// scanKey scans buf starting at i for the measurement and tag portion of the point.
+// It returns the ending position and the byte slice of key within buf. If there
+// are tags, they will be sorted if they are not already.
+func scanKey(buf []byte, i int) (int, []byte, error) {
+ start := skipWhitespace(buf, i)
+
+ i = start
+
+ // Determines whether the tags are sort, assume they are
+ sorted := true
+
+ // indices holds the indexes within buf of the start of each tag. For example,
+ // a buf of 'cpu,host=a,region=b,zone=c' would have indices slice of [4,11,20]
+ // which indicates that the first tag starts at buf[4], seconds at buf[11], and
+ // last at buf[20]
+ indices := make([]int, 100)
+
+ // tracks how many commas we've seen so we know how many values are indices.
+ // Since indices is an arbitrarily large slice,
+ // we need to know how many values in the buffer are in use.
+ commas := 0
+
+ // First scan the Point's measurement.
+ state, i, err := scanMeasurement(buf, i)
+ if err != nil {
+ return i, buf[start:i], err
+ }
+
+ // Optionally scan tags if needed.
+ if state == tagKeyState {
+ i, commas, indices, err = scanTags(buf, i, indices)
+ if err != nil {
+ return i, buf[start:i], err
+ }
+ }
+
+ // Now we know where the key region is within buf, and the location of tags, we
+ // need to determine if duplicate tags exist and if the tags are sorted. This iterates
+ // over the list comparing each tag in the sequence with each other.
+ for j := 0; j < commas-1; j++ {
+ // get the left and right tags
+ _, left := scanTo(buf[indices[j]:indices[j+1]-1], 0, '=')
+ _, right := scanTo(buf[indices[j+1]:indices[j+2]-1], 0, '=')
+
+ // If left is greater than right, the tags are not sorted. We do not have to
+ // continue because the short path no longer works.
+ // If the tags are equal, then there are duplicate tags, and we should abort.
+ // If the tags are not sorted, this pass may not find duplicate tags and we
+ // need to do a more exhaustive search later.
+ if cmp := bytes.Compare(left, right); cmp > 0 {
+ sorted = false
+ break
+ } else if cmp == 0 {
+ return i, buf[start:i], fmt.Errorf("duplicate tags")
+ }
+ }
+
+ // If the tags are not sorted, then sort them. This sort is inline and
+ // uses the tag indices we created earlier. The actual buffer is not sorted, the
+ // indices are using the buffer for value comparison. After the indices are sorted,
+ // the buffer is reconstructed from the sorted indices.
+ if !sorted && commas > 0 {
+ // Get the measurement name for later
+ measurement := buf[start : indices[0]-1]
+
+ // Sort the indices
+ indices := indices[:commas]
+ insertionSort(0, commas, buf, indices)
+
+ // Create a new key using the measurement and sorted indices
+ b := make([]byte, len(buf[start:i]))
+ pos := copy(b, measurement)
+ for _, i := range indices {
+ b[pos] = ','
+ pos++
+ _, v := scanToSpaceOr(buf, i, ',')
+ pos += copy(b[pos:], v)
+ }
+
+ // Check again for duplicate tags now that the tags are sorted.
+ for j := 0; j < commas-1; j++ {
+ // get the left and right tags
+ _, left := scanTo(buf[indices[j]:], 0, '=')
+ _, right := scanTo(buf[indices[j+1]:], 0, '=')
+
+ // If the tags are equal, then there are duplicate tags, and we should abort.
+ // If the tags are not sorted, this pass may not find duplicate tags and we
+ // need to do a more exhaustive search later.
+ if bytes.Equal(left, right) {
+ return i, b, fmt.Errorf("duplicate tags")
+ }
+ }
+
+ return i, b, nil
+ }
+
+ return i, buf[start:i], nil
+}
+
+// The following constants allow us to specify which state to move to
+// next, when scanning sections of a Point.
+const (
+ tagKeyState = iota
+ tagValueState
+ fieldsState
+)
+
+// scanMeasurement examines the measurement part of a Point, returning
+// the next state to move to, and the current location in the buffer.
+func scanMeasurement(buf []byte, i int) (int, int, error) {
+ // Check first byte of measurement, anything except a comma is fine.
+ // It can't be a space, since whitespace is stripped prior to this
+ // function call.
+ if i >= len(buf) || buf[i] == ',' {
+ return -1, i, fmt.Errorf("missing measurement")
+ }
+
+ for {
+ i++
+ if i >= len(buf) {
+ // cpu
+ return -1, i, fmt.Errorf("missing fields")
+ }
+
+ if buf[i-1] == '\\' {
+ // Skip character (it's escaped).
+ continue
+ }
+
+ // Unescaped comma; move onto scanning the tags.
+ if buf[i] == ',' {
+ return tagKeyState, i + 1, nil
+ }
+
+ // Unescaped space; move onto scanning the fields.
+ if buf[i] == ' ' {
+ // cpu value=1.0
+ return fieldsState, i, nil
+ }
+ }
+}
+
+// scanTags examines all the tags in a Point, keeping track of and
+// returning the updated indices slice, number of commas and location
+// in buf where to start examining the Point fields.
+func scanTags(buf []byte, i int, indices []int) (int, int, []int, error) {
+ var (
+ err error
+ commas int
+ state = tagKeyState
+ )
+
+ for {
+ switch state {
+ case tagKeyState:
+ // Grow our indices slice if we have too many tags.
+ if commas >= len(indices) {
+ newIndics := make([]int, cap(indices)*2)
+ copy(newIndics, indices)
+ indices = newIndics
+ }
+ indices[commas] = i
+ commas++
+
+ i, err = scanTagsKey(buf, i)
+ state = tagValueState // tag value always follows a tag key
+ case tagValueState:
+ state, i, err = scanTagsValue(buf, i)
+ case fieldsState:
+ indices[commas] = i + 1
+ return i, commas, indices, nil
+ }
+
+ if err != nil {
+ return i, commas, indices, err
+ }
+ }
+}
+
+// scanTagsKey scans each character in a tag key.
+func scanTagsKey(buf []byte, i int) (int, error) {
+ // First character of the key.
+ if i >= len(buf) || buf[i] == ' ' || buf[i] == ',' || buf[i] == '=' {
+ // cpu,{'', ' ', ',', '='}
+ return i, fmt.Errorf("missing tag key")
+ }
+
+ // Examine each character in the tag key until we hit an unescaped
+ // equals (the tag value), or we hit an error (i.e., unescaped
+ // space or comma).
+ for {
+ i++
+
+ // Either we reached the end of the buffer or we hit an
+ // unescaped comma or space.
+ if i >= len(buf) ||
+ ((buf[i] == ' ' || buf[i] == ',') && buf[i-1] != '\\') {
+ // cpu,tag{'', ' ', ','}
+ return i, fmt.Errorf("missing tag value")
+ }
+
+ if buf[i] == '=' && buf[i-1] != '\\' {
+ // cpu,tag=
+ return i + 1, nil
+ }
+ }
+}
+
+// scanTagsValue scans each character in a tag value.
+func scanTagsValue(buf []byte, i int) (int, int, error) {
+ // Tag value cannot be empty.
+ if i >= len(buf) || buf[i] == ',' || buf[i] == ' ' {
+ // cpu,tag={',', ' '}
+ return -1, i, fmt.Errorf("missing tag value")
+ }
+
+ // Examine each character in the tag value until we hit an unescaped
+ // comma (move onto next tag key), an unescaped space (move onto
+ // fields), or we error out.
+ for {
+ i++
+ if i >= len(buf) {
+ // cpu,tag=value
+ return -1, i, fmt.Errorf("missing fields")
+ }
+
+ // An unescaped equals sign is an invalid tag value.
+ if buf[i] == '=' && buf[i-1] != '\\' {
+ // cpu,tag={'=', 'fo=o'}
+ return -1, i, fmt.Errorf("invalid tag format")
+ }
+
+ if buf[i] == ',' && buf[i-1] != '\\' {
+ // cpu,tag=foo,
+ return tagKeyState, i + 1, nil
+ }
+
+ // cpu,tag=foo value=1.0
+ // cpu, tag=foo\= value=1.0
+ if buf[i] == ' ' && buf[i-1] != '\\' {
+ return fieldsState, i, nil
+ }
+ }
+}
+
+func insertionSort(l, r int, buf []byte, indices []int) {
+ for i := l + 1; i < r; i++ {
+ for j := i; j > l && less(buf, indices, j, j-1); j-- {
+ indices[j], indices[j-1] = indices[j-1], indices[j]
+ }
+ }
+}
+
+func less(buf []byte, indices []int, i, j int) bool {
+ // This grabs the tag names for i & j, it ignores the values
+ _, a := scanTo(buf, indices[i], '=')
+ _, b := scanTo(buf, indices[j], '=')
+ return bytes.Compare(a, b) < 0
+}
+
+// scanFields scans buf, starting at i for the fields section of a point. It returns
+// the ending position and the byte slice of the fields within buf.
+func scanFields(buf []byte, i int) (int, []byte, error) {
+ start := skipWhitespace(buf, i)
+ i = start
+ quoted := false
+
+ // tracks how many '=' we've seen
+ equals := 0
+
+ // tracks how many commas we've seen
+ commas := 0
+
+ for {
+ // reached the end of buf?
+ if i >= len(buf) {
+ break
+ }
+
+ // escaped characters?
+ if buf[i] == '\\' && i+1 < len(buf) {
+ i += 2
+ continue
+ }
+
+ // If the value is quoted, scan until we get to the end quote
+ // Only quote values in the field value since quotes are not significant
+ // in the field key
+ if buf[i] == '"' && equals > commas {
+ quoted = !quoted
+ i++
+ continue
+ }
+
+ // If we see an =, ensure that there is at least on char before and after it
+ if buf[i] == '=' && !quoted {
+ equals++
+
+ // check for "... =123" but allow "a\ =123"
+ if buf[i-1] == ' ' && buf[i-2] != '\\' {
+ return i, buf[start:i], fmt.Errorf("missing field key")
+ }
+
+ // check for "...a=123,=456" but allow "a=123,a\,=456"
+ if buf[i-1] == ',' && buf[i-2] != '\\' {
+ return i, buf[start:i], fmt.Errorf("missing field key")
+ }
+
+ // check for "... value="
+ if i+1 >= len(buf) {
+ return i, buf[start:i], fmt.Errorf("missing field value")
+ }
+
+ // check for "... value=,value2=..."
+ if buf[i+1] == ',' || buf[i+1] == ' ' {
+ return i, buf[start:i], fmt.Errorf("missing field value")
+ }
+
+ if isNumeric(buf[i+1]) || buf[i+1] == '-' || buf[i+1] == 'N' || buf[i+1] == 'n' {
+ var err error
+ i, err = scanNumber(buf, i+1)
+ if err != nil {
+ return i, buf[start:i], err
+ }
+ continue
+ }
+ // If next byte is not a double-quote, the value must be a boolean
+ if buf[i+1] != '"' {
+ var err error
+ i, _, err = scanBoolean(buf, i+1)
+ if err != nil {
+ return i, buf[start:i], err
+ }
+ continue
+ }
+ }
+
+ if buf[i] == ',' && !quoted {
+ commas++
+ }
+
+ // reached end of block?
+ if buf[i] == ' ' && !quoted {
+ break
+ }
+ i++
+ }
+
+ if quoted {
+ return i, buf[start:i], fmt.Errorf("unbalanced quotes")
+ }
+
+ // check that all field sections had key and values (e.g. prevent "a=1,b"
+ if equals == 0 || commas != equals-1 {
+ return i, buf[start:i], fmt.Errorf("invalid field format")
+ }
+
+ return i, buf[start:i], nil
+}
+
+// scanTime scans buf, starting at i for the time section of a point. It
+// returns the ending position and the byte slice of the timestamp within buf
+// and and error if the timestamp is not in the correct numeric format.
+func scanTime(buf []byte, i int) (int, []byte, error) {
+ start := skipWhitespace(buf, i)
+ i = start
+
+ for {
+ // reached the end of buf?
+ if i >= len(buf) {
+ break
+ }
+
+ // Reached end of block or trailing whitespace?
+ if buf[i] == '\n' || buf[i] == ' ' {
+ break
+ }
+
+ // Handle negative timestamps
+ if i == start && buf[i] == '-' {
+ i++
+ continue
+ }
+
+ // Timestamps should be integers, make sure they are so we don't need
+ // to actually parse the timestamp until needed.
+ if buf[i] < '0' || buf[i] > '9' {
+ return i, buf[start:i], fmt.Errorf("bad timestamp")
+ }
+ i++
+ }
+ return i, buf[start:i], nil
+}
+
+func isNumeric(b byte) bool {
+ return (b >= '0' && b <= '9') || b == '.'
+}
+
+// scanNumber returns the end position within buf, start at i after
+// scanning over buf for an integer, or float. It returns an
+// error if a invalid number is scanned.
+func scanNumber(buf []byte, i int) (int, error) {
+ start := i
+ var isInt bool
+
+ // Is negative number?
+ if i < len(buf) && buf[i] == '-' {
+ i++
+ // There must be more characters now, as just '-' is illegal.
+ if i == len(buf) {
+ return i, ErrInvalidNumber
+ }
+ }
+
+ // how many decimal points we've see
+ decimal := false
+
+ // indicates the number is float in scientific notation
+ scientific := false
+
+ for {
+ if i >= len(buf) {
+ break
+ }
+
+ if buf[i] == ',' || buf[i] == ' ' {
+ break
+ }
+
+ if buf[i] == 'i' && i > start && !isInt {
+ isInt = true
+ i++
+ continue
+ }
+
+ if buf[i] == '.' {
+ // Can't have more than 1 decimal (e.g. 1.1.1 should fail)
+ if decimal {
+ return i, ErrInvalidNumber
+ }
+ decimal = true
+ }
+
+ // `e` is valid for floats but not as the first char
+ if i > start && (buf[i] == 'e' || buf[i] == 'E') {
+ scientific = true
+ i++
+ continue
+ }
+
+ // + and - are only valid at this point if they follow an e (scientific notation)
+ if (buf[i] == '+' || buf[i] == '-') && (buf[i-1] == 'e' || buf[i-1] == 'E') {
+ i++
+ continue
+ }
+
+ // NaN is an unsupported value
+ if i+2 < len(buf) && (buf[i] == 'N' || buf[i] == 'n') {
+ return i, ErrInvalidNumber
+ }
+
+ if !isNumeric(buf[i]) {
+ return i, ErrInvalidNumber
+ }
+ i++
+ }
+
+ if isInt && (decimal || scientific) {
+ return i, ErrInvalidNumber
+ }
+
+ numericDigits := i - start
+ if isInt {
+ numericDigits--
+ }
+ if decimal {
+ numericDigits--
+ }
+ if buf[start] == '-' {
+ numericDigits--
+ }
+
+ if numericDigits == 0 {
+ return i, ErrInvalidNumber
+ }
+
+ // It's more common that numbers will be within min/max range for their type but we need to prevent
+ // out or range numbers from being parsed successfully. This uses some simple heuristics to decide
+ // if we should parse the number to the actual type. It does not do it all the time because it incurs
+ // extra allocations and we end up converting the type again when writing points to disk.
+ if isInt {
+ // Make sure the last char is an 'i' for integers (e.g. 9i10 is not valid)
+ if buf[i-1] != 'i' {
+ return i, ErrInvalidNumber
+ }
+ // Parse the int to check bounds the number of digits could be larger than the max range
+ // We subtract 1 from the index to remove the `i` from our tests
+ if len(buf[start:i-1]) >= maxInt64Digits || len(buf[start:i-1]) >= minInt64Digits {
+ if _, err := parseIntBytes(buf[start:i-1], 10, 64); err != nil {
+ return i, fmt.Errorf("unable to parse integer %s: %s", buf[start:i-1], err)
+ }
+ }
+ } else {
+ // Parse the float to check bounds if it's scientific or the number of digits could be larger than the max range
+ if scientific || len(buf[start:i]) >= maxFloat64Digits || len(buf[start:i]) >= minFloat64Digits {
+ if _, err := parseFloatBytes(buf[start:i], 10); err != nil {
+ return i, fmt.Errorf("invalid float")
+ }
+ }
+ }
+
+ return i, nil
+}
+
+// scanBoolean returns the end position within buf, start at i after
+// scanning over buf for boolean. Valid values for a boolean are
+// t, T, true, TRUE, f, F, false, FALSE. It returns an error if a invalid boolean
+// is scanned.
+func scanBoolean(buf []byte, i int) (int, []byte, error) {
+ start := i
+
+ if i < len(buf) && (buf[i] != 't' && buf[i] != 'f' && buf[i] != 'T' && buf[i] != 'F') {
+ return i, buf[start:i], fmt.Errorf("invalid boolean")
+ }
+
+ i++
+ for {
+ if i >= len(buf) {
+ break
+ }
+
+ if buf[i] == ',' || buf[i] == ' ' {
+ break
+ }
+ i++
+ }
+
+ // Single char bool (t, T, f, F) is ok
+ if i-start == 1 {
+ return i, buf[start:i], nil
+ }
+
+ // length must be 4 for true or TRUE
+ if (buf[start] == 't' || buf[start] == 'T') && i-start != 4 {
+ return i, buf[start:i], fmt.Errorf("invalid boolean")
+ }
+
+ // length must be 5 for false or FALSE
+ if (buf[start] == 'f' || buf[start] == 'F') && i-start != 5 {
+ return i, buf[start:i], fmt.Errorf("invalid boolean")
+ }
+
+ // Otherwise
+ valid := false
+ switch buf[start] {
+ case 't':
+ valid = bytes.Equal(buf[start:i], []byte("true"))
+ case 'f':
+ valid = bytes.Equal(buf[start:i], []byte("false"))
+ case 'T':
+ valid = bytes.Equal(buf[start:i], []byte("TRUE")) || bytes.Equal(buf[start:i], []byte("True"))
+ case 'F':
+ valid = bytes.Equal(buf[start:i], []byte("FALSE")) || bytes.Equal(buf[start:i], []byte("False"))
+ }
+
+ if !valid {
+ return i, buf[start:i], fmt.Errorf("invalid boolean")
+ }
+
+ return i, buf[start:i], nil
+
+}
+
+// skipWhitespace returns the end position within buf, starting at i after
+// scanning over spaces in tags.
+func skipWhitespace(buf []byte, i int) int {
+ for i < len(buf) {
+ if buf[i] != ' ' && buf[i] != '\t' && buf[i] != 0 {
+ break
+ }
+ i++
+ }
+ return i
+}
+
+// scanLine returns the end position in buf and the next line found within
+// buf.
+func scanLine(buf []byte, i int) (int, []byte) {
+ start := i
+ quoted := false
+ fields := false
+
+ // tracks how many '=' and commas we've seen
+ // this duplicates some of the functionality in scanFields
+ equals := 0
+ commas := 0
+ for {
+ // reached the end of buf?
+ if i >= len(buf) {
+ break
+ }
+
+ // skip past escaped characters
+ if buf[i] == '\\' {
+ i += 2
+ continue
+ }
+
+ if buf[i] == ' ' {
+ fields = true
+ }
+
+ // If we see a double quote, makes sure it is not escaped
+ if fields {
+ if !quoted && buf[i] == '=' {
+ i++
+ equals++
+ continue
+ } else if !quoted && buf[i] == ',' {
+ i++
+ commas++
+ continue
+ } else if buf[i] == '"' && equals > commas {
+ i++
+ quoted = !quoted
+ continue
+ }
+ }
+
+ if buf[i] == '\n' && !quoted {
+ break
+ }
+
+ i++
+ }
+
+ return i, buf[start:i]
+}
+
+// scanTo returns the end position in buf and the next consecutive block
+// of bytes, starting from i and ending with stop byte, where stop byte
+// has not been escaped.
+//
+// If there are leading spaces, they are skipped.
+func scanTo(buf []byte, i int, stop byte) (int, []byte) {
+ start := i
+ for {
+ // reached the end of buf?
+ if i >= len(buf) {
+ break
+ }
+
+ // Reached unescaped stop value?
+ if buf[i] == stop && (i == 0 || buf[i-1] != '\\') {
+ break
+ }
+ i++
+ }
+
+ return i, buf[start:i]
+}
+
+// scanTo returns the end position in buf and the next consecutive block
+// of bytes, starting from i and ending with stop byte. If there are leading
+// spaces, they are skipped.
+func scanToSpaceOr(buf []byte, i int, stop byte) (int, []byte) {
+ start := i
+ if buf[i] == stop || buf[i] == ' ' {
+ return i, buf[start:i]
+ }
+
+ for {
+ i++
+ if buf[i-1] == '\\' {
+ continue
+ }
+
+ // reached the end of buf?
+ if i >= len(buf) {
+ return i, buf[start:i]
+ }
+
+ // reached end of block?
+ if buf[i] == stop || buf[i] == ' ' {
+ return i, buf[start:i]
+ }
+ }
+}
+
+func scanTagValue(buf []byte, i int) (int, []byte) {
+ start := i
+ for {
+ if i >= len(buf) {
+ break
+ }
+
+ if buf[i] == ',' && buf[i-1] != '\\' {
+ break
+ }
+ i++
+ }
+ if i > len(buf) {
+ return i, nil
+ }
+ return i, buf[start:i]
+}
+
+func scanFieldValue(buf []byte, i int) (int, []byte) {
+ start := i
+ quoted := false
+ for i < len(buf) {
+ // Only escape char for a field value is a double-quote and backslash
+ if buf[i] == '\\' && i+1 < len(buf) && (buf[i+1] == '"' || buf[i+1] == '\\') {
+ i += 2
+ continue
+ }
+
+ // Quoted value? (e.g. string)
+ if buf[i] == '"' {
+ i++
+ quoted = !quoted
+ continue
+ }
+
+ if buf[i] == ',' && !quoted {
+ break
+ }
+ i++
+ }
+ return i, buf[start:i]
+}
+
+func escapeMeasurement(in []byte) []byte {
+ for b, esc := range measurementEscapeCodes {
+ in = bytes.Replace(in, []byte{b}, esc, -1)
+ }
+ return in
+}
+
+func unescapeMeasurement(in []byte) []byte {
+ for b, esc := range measurementEscapeCodes {
+ in = bytes.Replace(in, esc, []byte{b}, -1)
+ }
+ return in
+}
+
+func escapeTag(in []byte) []byte {
+ for b, esc := range tagEscapeCodes {
+ if bytes.IndexByte(in, b) != -1 {
+ in = bytes.Replace(in, []byte{b}, esc, -1)
+ }
+ }
+ return in
+}
+
+func unescapeTag(in []byte) []byte {
+ if bytes.IndexByte(in, '\\') == -1 {
+ return in
+ }
+
+ for b, esc := range tagEscapeCodes {
+ if bytes.IndexByte(in, b) != -1 {
+ in = bytes.Replace(in, esc, []byte{b}, -1)
+ }
+ }
+ return in
+}
+
+// escapeStringFieldReplacer replaces double quotes and backslashes
+// with the same character preceded by a backslash.
+// As of Go 1.7 this benchmarked better in allocations and CPU time
+// compared to iterating through a string byte-by-byte and appending to a new byte slice,
+// calling strings.Replace twice, and better than (*Regex).ReplaceAllString.
+var escapeStringFieldReplacer = strings.NewReplacer(`"`, `\"`, `\`, `\\`)
+
+// EscapeStringField returns a copy of in with any double quotes or
+// backslashes with escaped values.
+func EscapeStringField(in string) string {
+ return escapeStringFieldReplacer.Replace(in)
+}
+
+// unescapeStringField returns a copy of in with any escaped double-quotes
+// or backslashes unescaped.
+func unescapeStringField(in string) string {
+ if strings.IndexByte(in, '\\') == -1 {
+ return in
+ }
+
+ var out []byte
+ i := 0
+ for {
+ if i >= len(in) {
+ break
+ }
+ // unescape backslashes
+ if in[i] == '\\' && i+1 < len(in) && in[i+1] == '\\' {
+ out = append(out, '\\')
+ i += 2
+ continue
+ }
+ // unescape double-quotes
+ if in[i] == '\\' && i+1 < len(in) && in[i+1] == '"' {
+ out = append(out, '"')
+ i += 2
+ continue
+ }
+ out = append(out, in[i])
+ i++
+
+ }
+ return string(out)
+}
+
+// NewPoint returns a new point with the given measurement name, tags, fields and timestamp. If
+// an unsupported field value (NaN) or out of range time is passed, this function returns an error.
+func NewPoint(name string, tags Tags, fields Fields, t time.Time) (Point, error) {
+ key, err := pointKey(name, tags, fields, t)
+ if err != nil {
+ return nil, err
+ }
+
+ return &point{
+ key: key,
+ time: t,
+ fields: fields.MarshalBinary(),
+ }, nil
+}
+
+// pointKey checks some basic requirements for valid points, and returns the
+// key, along with an possible error.
+func pointKey(measurement string, tags Tags, fields Fields, t time.Time) ([]byte, error) {
+ if len(fields) == 0 {
+ return nil, ErrPointMustHaveAField
+ }
+
+ if !t.IsZero() {
+ if err := CheckTime(t); err != nil {
+ return nil, err
+ }
+ }
+
+ for key, value := range fields {
+ switch value := value.(type) {
+ case float64:
+ // Ensure the caller validates and handles invalid field values
+ if math.IsNaN(value) {
+ return nil, fmt.Errorf("NaN is an unsupported value for field %s", key)
+ }
+ case float32:
+ // Ensure the caller validates and handles invalid field values
+ if math.IsNaN(float64(value)) {
+ return nil, fmt.Errorf("NaN is an unsupported value for field %s", key)
+ }
+ }
+ if len(key) == 0 {
+ return nil, fmt.Errorf("all fields must have non-empty names")
+ }
+ }
+
+ key := MakeKey([]byte(measurement), tags)
+ if len(key) > MaxKeyLength {
+ return nil, fmt.Errorf("max key length exceeded: %v > %v", len(key), MaxKeyLength)
+ }
+
+ return key, nil
+}
+
+// NewPointFromBytes returns a new Point from a marshalled Point.
+func NewPointFromBytes(b []byte) (Point, error) {
+ p := &point{}
+ if err := p.UnmarshalBinary(b); err != nil {
+ return nil, err
+ }
+ fields, err := p.Fields()
+ if err != nil {
+ return nil, err
+ }
+ if len(fields) == 0 {
+ return nil, ErrPointMustHaveAField
+ }
+ return p, nil
+}
+
+// MustNewPoint returns a new point with the given measurement name, tags, fields and timestamp. If
+// an unsupported field value (NaN) is passed, this function panics.
+func MustNewPoint(name string, tags Tags, fields Fields, time time.Time) Point {
+ pt, err := NewPoint(name, tags, fields, time)
+ if err != nil {
+ panic(err.Error())
+ }
+ return pt
+}
+
+// Key returns the key (measurement joined with tags) of the point.
+func (p *point) Key() []byte {
+ return p.key
+}
+
+func (p *point) name() []byte {
+ _, name := scanTo(p.key, 0, ',')
+ return name
+}
+
+// Name return the measurement name for the point.
+func (p *point) Name() string {
+ if p.cachedName != "" {
+ return p.cachedName
+ }
+ p.cachedName = string(escape.Unescape(p.name()))
+ return p.cachedName
+}
+
+// SetName updates the measurement name for the point.
+func (p *point) SetName(name string) {
+ p.cachedName = ""
+ p.key = MakeKey([]byte(name), p.Tags())
+}
+
+// Time return the timestamp for the point.
+func (p *point) Time() time.Time {
+ return p.time
+}
+
+// SetTime updates the timestamp for the point.
+func (p *point) SetTime(t time.Time) {
+ p.time = t
+}
+
+// Round will round the timestamp of the point to the given duration.
+func (p *point) Round(d time.Duration) {
+ p.time = p.time.Round(d)
+}
+
+// Tags returns the tag set for the point.
+func (p *point) Tags() Tags {
+ if p.cachedTags != nil {
+ return p.cachedTags
+ }
+ p.cachedTags = parseTags(p.key)
+ return p.cachedTags
+}
+
+func parseTags(buf []byte) Tags {
+ if len(buf) == 0 {
+ return nil
+ }
+
+ pos, name := scanTo(buf, 0, ',')
+
+ // it's an empty key, so there are no tags
+ if len(name) == 0 {
+ return nil
+ }
+
+ tags := make(Tags, 0, bytes.Count(buf, []byte(",")))
+ hasEscape := bytes.IndexByte(buf, '\\') != -1
+
+ i := pos + 1
+ var key, value []byte
+ for {
+ if i >= len(buf) {
+ break
+ }
+ i, key = scanTo(buf, i, '=')
+ i, value = scanTagValue(buf, i+1)
+
+ if len(value) == 0 {
+ continue
+ }
+
+ if hasEscape {
+ tags = append(tags, Tag{Key: unescapeTag(key), Value: unescapeTag(value)})
+ } else {
+ tags = append(tags, Tag{Key: key, Value: value})
+ }
+
+ i++
+ }
+
+ return tags
+}
+
+// MakeKey creates a key for a set of tags.
+func MakeKey(name []byte, tags Tags) []byte {
+ // unescape the name and then re-escape it to avoid double escaping.
+ // The key should always be stored in escaped form.
+ return append(escapeMeasurement(unescapeMeasurement(name)), tags.HashKey()...)
+}
+
+// SetTags replaces the tags for the point.
+func (p *point) SetTags(tags Tags) {
+ p.key = MakeKey([]byte(p.Name()), tags)
+ p.cachedTags = tags
+}
+
+// AddTag adds or replaces a tag value for a point.
+func (p *point) AddTag(key, value string) {
+ tags := p.Tags()
+ tags = append(tags, Tag{Key: []byte(key), Value: []byte(value)})
+ sort.Sort(tags)
+ p.cachedTags = tags
+ p.key = MakeKey([]byte(p.Name()), tags)
+}
+
+// Fields returns the fields for the point.
+func (p *point) Fields() (Fields, error) {
+ if p.cachedFields != nil {
+ return p.cachedFields, nil
+ }
+ cf, err := p.unmarshalBinary()
+ if err != nil {
+ return nil, err
+ }
+ p.cachedFields = cf
+ return p.cachedFields, nil
+}
+
+// SetPrecision will round a time to the specified precision.
+func (p *point) SetPrecision(precision string) {
+ switch precision {
+ case "n":
+ case "u":
+ p.SetTime(p.Time().Truncate(time.Microsecond))
+ case "ms":
+ p.SetTime(p.Time().Truncate(time.Millisecond))
+ case "s":
+ p.SetTime(p.Time().Truncate(time.Second))
+ case "m":
+ p.SetTime(p.Time().Truncate(time.Minute))
+ case "h":
+ p.SetTime(p.Time().Truncate(time.Hour))
+ }
+}
+
+// String returns the string representation of the point.
+func (p *point) String() string {
+ if p.Time().IsZero() {
+ return string(p.Key()) + " " + string(p.fields)
+ }
+ return string(p.Key()) + " " + string(p.fields) + " " + strconv.FormatInt(p.UnixNano(), 10)
+}
+
+// AppendString appends the string representation of the point to buf.
+func (p *point) AppendString(buf []byte) []byte {
+ buf = append(buf, p.key...)
+ buf = append(buf, ' ')
+ buf = append(buf, p.fields...)
+
+ if !p.time.IsZero() {
+ buf = append(buf, ' ')
+ buf = strconv.AppendInt(buf, p.UnixNano(), 10)
+ }
+
+ return buf
+}
+
+// StringSize returns the length of the string that would be returned by String().
+func (p *point) StringSize() int {
+ size := len(p.key) + len(p.fields) + 1
+
+ if !p.time.IsZero() {
+ digits := 1 // even "0" has one digit
+ t := p.UnixNano()
+ if t < 0 {
+ // account for negative sign, then negate
+ digits++
+ t = -t
+ }
+ for t > 9 { // already accounted for one digit
+ digits++
+ t /= 10
+ }
+ size += digits + 1 // digits and a space
+ }
+
+ return size
+}
+
+// MarshalBinary returns a binary representation of the point.
+func (p *point) MarshalBinary() ([]byte, error) {
+ if len(p.fields) == 0 {
+ return nil, ErrPointMustHaveAField
+ }
+
+ tb, err := p.time.MarshalBinary()
+ if err != nil {
+ return nil, err
+ }
+
+ b := make([]byte, 8+len(p.key)+len(p.fields)+len(tb))
+ i := 0
+
+ binary.BigEndian.PutUint32(b[i:], uint32(len(p.key)))
+ i += 4
+
+ i += copy(b[i:], p.key)
+
+ binary.BigEndian.PutUint32(b[i:i+4], uint32(len(p.fields)))
+ i += 4
+
+ i += copy(b[i:], p.fields)
+
+ copy(b[i:], tb)
+ return b, nil
+}
+
+// UnmarshalBinary decodes a binary representation of the point into a point struct.
+func (p *point) UnmarshalBinary(b []byte) error {
+ var i int
+ keyLen := int(binary.BigEndian.Uint32(b[:4]))
+ i += int(4)
+
+ p.key = b[i : i+keyLen]
+ i += keyLen
+
+ fieldLen := int(binary.BigEndian.Uint32(b[i : i+4]))
+ i += int(4)
+
+ p.fields = b[i : i+fieldLen]
+ i += fieldLen
+
+ p.time = time.Now()
+ p.time.UnmarshalBinary(b[i:])
+ return nil
+}
+
+// PrecisionString returns a string representation of the point. If there
+// is a timestamp associated with the point then it will be specified in the
+// given unit.
+func (p *point) PrecisionString(precision string) string {
+ if p.Time().IsZero() {
+ return fmt.Sprintf("%s %s", p.Key(), string(p.fields))
+ }
+ return fmt.Sprintf("%s %s %d", p.Key(), string(p.fields),
+ p.UnixNano()/GetPrecisionMultiplier(precision))
+}
+
+// RoundedString returns a string representation of the point. If there
+// is a timestamp associated with the point, then it will be rounded to the
+// given duration.
+func (p *point) RoundedString(d time.Duration) string {
+ if p.Time().IsZero() {
+ return fmt.Sprintf("%s %s", p.Key(), string(p.fields))
+ }
+ return fmt.Sprintf("%s %s %d", p.Key(), string(p.fields),
+ p.time.Round(d).UnixNano())
+}
+
+func (p *point) unmarshalBinary() (Fields, error) {
+ iter := p.FieldIterator()
+ fields := make(Fields, 8)
+ for iter.Next() {
+ if len(iter.FieldKey()) == 0 {
+ continue
+ }
+ switch iter.Type() {
+ case Float:
+ v, err := iter.FloatValue()
+ if err != nil {
+ return nil, fmt.Errorf("unable to unmarshal field %s: %s", string(iter.FieldKey()), err)
+ }
+ fields[string(iter.FieldKey())] = v
+ case Integer:
+ v, err := iter.IntegerValue()
+ if err != nil {
+ return nil, fmt.Errorf("unable to unmarshal field %s: %s", string(iter.FieldKey()), err)
+ }
+ fields[string(iter.FieldKey())] = v
+ case String:
+ fields[string(iter.FieldKey())] = iter.StringValue()
+ case Boolean:
+ v, err := iter.BooleanValue()
+ if err != nil {
+ return nil, fmt.Errorf("unable to unmarshal field %s: %s", string(iter.FieldKey()), err)
+ }
+ fields[string(iter.FieldKey())] = v
+ }
+ }
+ return fields, nil
+}
+
+// HashID returns a non-cryptographic checksum of the point's key.
+func (p *point) HashID() uint64 {
+ h := NewInlineFNV64a()
+ h.Write(p.key)
+ sum := h.Sum64()
+ return sum
+}
+
+// UnixNano returns the timestamp of the point as nanoseconds since Unix epoch.
+func (p *point) UnixNano() int64 {
+ return p.Time().UnixNano()
+}
+
+// Split will attempt to return multiple points with the same timestamp whose
+// string representations are no longer than size. Points with a single field or
+// a point without a timestamp may exceed the requested size.
+func (p *point) Split(size int) []Point {
+ if p.time.IsZero() || len(p.String()) <= size {
+ return []Point{p}
+ }
+
+ // key string, timestamp string, spaces
+ size -= len(p.key) + len(strconv.FormatInt(p.time.UnixNano(), 10)) + 2
+
+ var points []Point
+ var start, cur int
+
+ for cur < len(p.fields) {
+ end, _ := scanTo(p.fields, cur, '=')
+ end, _ = scanFieldValue(p.fields, end+1)
+
+ if cur > start && end-start > size {
+ points = append(points, &point{
+ key: p.key,
+ time: p.time,
+ fields: p.fields[start : cur-1],
+ })
+ start = cur
+ }
+
+ cur = end + 1
+ }
+
+ points = append(points, &point{
+ key: p.key,
+ time: p.time,
+ fields: p.fields[start:],
+ })
+
+ return points
+}
+
+// Tag represents a single key/value tag pair.
+type Tag struct {
+ Key []byte
+ Value []byte
+}
+
+// Tags represents a sorted list of tags.
+type Tags []Tag
+
+// NewTags returns a new Tags from a map.
+func NewTags(m map[string]string) Tags {
+ if len(m) == 0 {
+ return nil
+ }
+ a := make(Tags, 0, len(m))
+ for k, v := range m {
+ a = append(a, Tag{Key: []byte(k), Value: []byte(v)})
+ }
+ sort.Sort(a)
+ return a
+}
+
+// Len implements sort.Interface.
+func (a Tags) Len() int { return len(a) }
+
+// Less implements sort.Interface.
+func (a Tags) Less(i, j int) bool { return bytes.Compare(a[i].Key, a[j].Key) == -1 }
+
+// Swap implements sort.Interface.
+func (a Tags) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
+
+// Get returns the value for a key.
+func (a Tags) Get(key []byte) []byte {
+ // OPTIMIZE: Use sort.Search if tagset is large.
+
+ for _, t := range a {
+ if bytes.Equal(t.Key, key) {
+ return t.Value
+ }
+ }
+ return nil
+}
+
+// GetString returns the string value for a string key.
+func (a Tags) GetString(key string) string {
+ return string(a.Get([]byte(key)))
+}
+
+// Set sets the value for a key.
+func (a *Tags) Set(key, value []byte) {
+ for _, t := range *a {
+ if bytes.Equal(t.Key, key) {
+ t.Value = value
+ return
+ }
+ }
+ *a = append(*a, Tag{Key: key, Value: value})
+ sort.Sort(*a)
+}
+
+// SetString sets the string value for a string key.
+func (a *Tags) SetString(key, value string) {
+ a.Set([]byte(key), []byte(value))
+}
+
+// Delete removes a tag by key.
+func (a *Tags) Delete(key []byte) {
+ for i, t := range *a {
+ if bytes.Equal(t.Key, key) {
+ copy((*a)[i:], (*a)[i+1:])
+ (*a)[len(*a)-1] = Tag{}
+ *a = (*a)[:len(*a)-1]
+ return
+ }
+ }
+}
+
+// Map returns a map representation of the tags.
+func (a Tags) Map() map[string]string {
+ m := make(map[string]string, len(a))
+ for _, t := range a {
+ m[string(t.Key)] = string(t.Value)
+ }
+ return m
+}
+
+// Merge merges the tags combining the two. If both define a tag with the
+// same key, the merged value overwrites the old value.
+// A new map is returned.
+func (a Tags) Merge(other map[string]string) Tags {
+ merged := make(map[string]string, len(a)+len(other))
+ for _, t := range a {
+ merged[string(t.Key)] = string(t.Value)
+ }
+ for k, v := range other {
+ merged[k] = v
+ }
+ return NewTags(merged)
+}
+
+// HashKey hashes all of a tag's keys.
+func (a Tags) HashKey() []byte {
+ // Empty maps marshal to empty bytes.
+ if len(a) == 0 {
+ return nil
+ }
+
+ escaped := make(Tags, 0, len(a))
+ for _, t := range a {
+ ek := escapeTag(t.Key)
+ ev := escapeTag(t.Value)
+
+ if len(ev) > 0 {
+ escaped = append(escaped, Tag{Key: ek, Value: ev})
+ }
+ }
+
+ // Extract keys and determine final size.
+ sz := len(escaped) + (len(escaped) * 2) // separators
+ keys := make([][]byte, len(escaped)+1)
+ for i, t := range escaped {
+ keys[i] = t.Key
+ sz += len(t.Key) + len(t.Value)
+ }
+ keys = keys[:len(escaped)]
+ sort.Sort(byteSlices(keys))
+
+ // Generate marshaled bytes.
+ b := make([]byte, sz)
+ buf := b
+ idx := 0
+ for i, k := range keys {
+ buf[idx] = ','
+ idx++
+ copy(buf[idx:idx+len(k)], k)
+ idx += len(k)
+ buf[idx] = '='
+ idx++
+ v := escaped[i].Value
+ copy(buf[idx:idx+len(v)], v)
+ idx += len(v)
+ }
+ return b[:idx]
+}
+
+// Fields represents a mapping between a Point's field names and their
+// values.
+type Fields map[string]interface{}
+
+func parseNumber(val []byte) (interface{}, error) {
+ if val[len(val)-1] == 'i' {
+ val = val[:len(val)-1]
+ return parseIntBytes(val, 10, 64)
+ }
+ for i := 0; i < len(val); i++ {
+ // If there is a decimal or an N (NaN), I (Inf), parse as float
+ if val[i] == '.' || val[i] == 'N' || val[i] == 'n' || val[i] == 'I' || val[i] == 'i' || val[i] == 'e' {
+ return parseFloatBytes(val, 64)
+ }
+ if val[i] < '0' && val[i] > '9' {
+ return string(val), nil
+ }
+ }
+ return parseFloatBytes(val, 64)
+}
+
+// FieldIterator retuns a FieldIterator that can be used to traverse the
+// fields of a point without constructing the in-memory map.
+func (p *point) FieldIterator() FieldIterator {
+ p.Reset()
+ return p
+}
+
+type fieldIterator struct {
+ start, end int
+ key, keybuf []byte
+ valueBuf []byte
+ fieldType FieldType
+}
+
+// Next indicates whether there any fields remaining.
+func (p *point) Next() bool {
+ p.it.start = p.it.end
+ if p.it.start >= len(p.fields) {
+ return false
+ }
+
+ p.it.end, p.it.key = scanTo(p.fields, p.it.start, '=')
+ if escape.IsEscaped(p.it.key) {
+ p.it.keybuf = escape.AppendUnescaped(p.it.keybuf[:0], p.it.key)
+ p.it.key = p.it.keybuf
+ }
+
+ p.it.end, p.it.valueBuf = scanFieldValue(p.fields, p.it.end+1)
+ p.it.end++
+
+ if len(p.it.valueBuf) == 0 {
+ p.it.fieldType = Empty
+ return true
+ }
+
+ c := p.it.valueBuf[0]
+
+ if c == '"' {
+ p.it.fieldType = String
+ return true
+ }
+
+ if strings.IndexByte(`0123456789-.nNiI`, c) >= 0 {
+ if p.it.valueBuf[len(p.it.valueBuf)-1] == 'i' {
+ p.it.fieldType = Integer
+ p.it.valueBuf = p.it.valueBuf[:len(p.it.valueBuf)-1]
+ } else {
+ p.it.fieldType = Float
+ }
+ return true
+ }
+
+ // to keep the same behavior that currently exists, default to boolean
+ p.it.fieldType = Boolean
+ return true
+}
+
+// FieldKey returns the key of the current field.
+func (p *point) FieldKey() []byte {
+ return p.it.key
+}
+
+// Type returns the FieldType of the current field.
+func (p *point) Type() FieldType {
+ return p.it.fieldType
+}
+
+// StringValue returns the string value of the current field.
+func (p *point) StringValue() string {
+ return unescapeStringField(string(p.it.valueBuf[1 : len(p.it.valueBuf)-1]))
+}
+
+// IntegerValue returns the integer value of the current field.
+func (p *point) IntegerValue() (int64, error) {
+ n, err := parseIntBytes(p.it.valueBuf, 10, 64)
+ if err != nil {
+ return 0, fmt.Errorf("unable to parse integer value %q: %v", p.it.valueBuf, err)
+ }
+ return n, nil
+}
+
+// BooleanValue returns the boolean value of the current field.
+func (p *point) BooleanValue() (bool, error) {
+ b, err := parseBoolBytes(p.it.valueBuf)
+ if err != nil {
+ return false, fmt.Errorf("unable to parse bool value %q: %v", p.it.valueBuf, err)
+ }
+ return b, nil
+}
+
+// FloatValue returns the float value of the current field.
+func (p *point) FloatValue() (float64, error) {
+ f, err := parseFloatBytes(p.it.valueBuf, 64)
+ if err != nil {
+ return 0, fmt.Errorf("unable to parse floating point value %q: %v", p.it.valueBuf, err)
+ }
+ return f, nil
+}
+
+// Delete deletes the current field.
+func (p *point) Delete() {
+ switch {
+ case p.it.end == p.it.start:
+ case p.it.end >= len(p.fields):
+ p.fields = p.fields[:p.it.start]
+ case p.it.start == 0:
+ p.fields = p.fields[p.it.end:]
+ default:
+ p.fields = append(p.fields[:p.it.start], p.fields[p.it.end:]...)
+ }
+
+ p.it.end = p.it.start
+ p.it.key = nil
+ p.it.valueBuf = nil
+ p.it.fieldType = Empty
+}
+
+// Reset resets the iterator to its initial state.
+func (p *point) Reset() {
+ p.it.fieldType = Empty
+ p.it.key = nil
+ p.it.valueBuf = nil
+ p.it.start = 0
+ p.it.end = 0
+}
+
+// MarshalBinary encodes all the fields to their proper type and returns the binary
+// represenation
+// NOTE: uint64 is specifically not supported due to potential overflow when we decode
+// again later to an int64
+// NOTE2: uint is accepted, and may be 64 bits, and is for some reason accepted...
+func (p Fields) MarshalBinary() []byte {
+ var b []byte
+ keys := make([]string, 0, len(p))
+
+ for k := range p {
+ keys = append(keys, k)
+ }
+
+ // Not really necessary, can probably be removed.
+ sort.Strings(keys)
+
+ for i, k := range keys {
+ if i > 0 {
+ b = append(b, ',')
+ }
+ b = appendField(b, k, p[k])
+ }
+
+ return b
+}
+
+func appendField(b []byte, k string, v interface{}) []byte {
+ b = append(b, []byte(escape.String(k))...)
+ b = append(b, '=')
+
+ // check popular types first
+ switch v := v.(type) {
+ case float64:
+ b = strconv.AppendFloat(b, v, 'f', -1, 64)
+ case int64:
+ b = strconv.AppendInt(b, v, 10)
+ b = append(b, 'i')
+ case string:
+ b = append(b, '"')
+ b = append(b, []byte(EscapeStringField(v))...)
+ b = append(b, '"')
+ case bool:
+ b = strconv.AppendBool(b, v)
+ case int32:
+ b = strconv.AppendInt(b, int64(v), 10)
+ b = append(b, 'i')
+ case int16:
+ b = strconv.AppendInt(b, int64(v), 10)
+ b = append(b, 'i')
+ case int8:
+ b = strconv.AppendInt(b, int64(v), 10)
+ b = append(b, 'i')
+ case int:
+ b = strconv.AppendInt(b, int64(v), 10)
+ b = append(b, 'i')
+ case uint32:
+ b = strconv.AppendInt(b, int64(v), 10)
+ b = append(b, 'i')
+ case uint16:
+ b = strconv.AppendInt(b, int64(v), 10)
+ b = append(b, 'i')
+ case uint8:
+ b = strconv.AppendInt(b, int64(v), 10)
+ b = append(b, 'i')
+ // TODO: 'uint' should be considered just as "dangerous" as a uint64,
+ // perhaps the value should be checked and capped at MaxInt64? We could
+ // then include uint64 as an accepted value
+ case uint:
+ b = strconv.AppendInt(b, int64(v), 10)
+ b = append(b, 'i')
+ case float32:
+ b = strconv.AppendFloat(b, float64(v), 'f', -1, 32)
+ case []byte:
+ b = append(b, v...)
+ case nil:
+ // skip
+ default:
+ // Can't determine the type, so convert to string
+ b = append(b, '"')
+ b = append(b, []byte(EscapeStringField(fmt.Sprintf("%v", v)))...)
+ b = append(b, '"')
+
+ }
+
+ return b
+}
+
+type byteSlices [][]byte
+
+func (a byteSlices) Len() int { return len(a) }
+func (a byteSlices) Less(i, j int) bool { return bytes.Compare(a[i], a[j]) == -1 }
+func (a byteSlices) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/4df63f3a/traffic_stats/vendor/github.com/influxdata/influxdb/models/rows.go
----------------------------------------------------------------------
diff --git a/traffic_stats/vendor/github.com/influxdata/influxdb/models/rows.go b/traffic_stats/vendor/github.com/influxdata/influxdb/models/rows.go
new file mode 100644
index 0000000..c087a48
--- /dev/null
+++ b/traffic_stats/vendor/github.com/influxdata/influxdb/models/rows.go
@@ -0,0 +1,62 @@
+package models
+
+import (
+ "sort"
+)
+
+// Row represents a single row returned from the execution of a statement.
+type Row struct {
+ Name string `json:"name,omitempty"`
+ Tags map[string]string `json:"tags,omitempty"`
+ Columns []string `json:"columns,omitempty"`
+ Values [][]interface{} `json:"values,omitempty"`
+ Partial bool `json:"partial,omitempty"`
+}
+
+// SameSeries returns true if r contains values for the same series as o.
+func (r *Row) SameSeries(o *Row) bool {
+ return r.tagsHash() == o.tagsHash() && r.Name == o.Name
+}
+
+// tagsHash returns a hash of tag key/value pairs.
+func (r *Row) tagsHash() uint64 {
+ h := NewInlineFNV64a()
+ keys := r.tagsKeys()
+ for _, k := range keys {
+ h.Write([]byte(k))
+ h.Write([]byte(r.Tags[k]))
+ }
+ return h.Sum64()
+}
+
+// tagKeys returns a sorted list of tag keys.
+func (r *Row) tagsKeys() []string {
+ a := make([]string, 0, len(r.Tags))
+ for k := range r.Tags {
+ a = append(a, k)
+ }
+ sort.Strings(a)
+ return a
+}
+
+// Rows represents a collection of rows. Rows implements sort.Interface.
+type Rows []*Row
+
+// Len implements sort.Interface.
+func (p Rows) Len() int { return len(p) }
+
+// Less implements sort.Interface.
+func (p Rows) Less(i, j int) bool {
+ // Sort by name first.
+ if p[i].Name != p[j].Name {
+ return p[i].Name < p[j].Name
+ }
+
+ // Sort by tag set hash. Tags don't have a meaningful sort order so we
+ // just compute a hash and sort by that instead. This allows the tests
+ // to receive rows in a predictable order every time.
+ return p[i].tagsHash() < p[j].tagsHash()
+}
+
+// Swap implements sort.Interface.
+func (p Rows) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/4df63f3a/traffic_stats/vendor/github.com/influxdata/influxdb/models/statistic.go
----------------------------------------------------------------------
diff --git a/traffic_stats/vendor/github.com/influxdata/influxdb/models/statistic.go b/traffic_stats/vendor/github.com/influxdata/influxdb/models/statistic.go
new file mode 100644
index 0000000..553e9d0
--- /dev/null
+++ b/traffic_stats/vendor/github.com/influxdata/influxdb/models/statistic.go
@@ -0,0 +1,42 @@
+package models
+
+// Statistic is the representation of a statistic used by the monitoring service.
+type Statistic struct {
+ Name string `json:"name"`
+ Tags map[string]string `json:"tags"`
+ Values map[string]interface{} `json:"values"`
+}
+
+// NewStatistic returns an initialized Statistic.
+func NewStatistic(name string) Statistic {
+ return Statistic{
+ Name: name,
+ Tags: make(map[string]string),
+ Values: make(map[string]interface{}),
+ }
+}
+
+// StatisticTags is a map that can be merged with others without causing
+// mutations to either map.
+type StatisticTags map[string]string
+
+// Merge creates a new map containing the merged contents of tags and t.
+// If both tags and the receiver map contain the same key, the value in tags
+// is used in the resulting map.
+//
+// Merge always returns a usable map.
+func (t StatisticTags) Merge(tags map[string]string) map[string]string {
+ // Add everything in tags to the result.
+ out := make(map[string]string, len(tags))
+ for k, v := range tags {
+ out[k] = v
+ }
+
+ // Only add values from t that don't appear in tags.
+ for k, v := range t {
+ if _, ok := tags[k]; !ok {
+ out[k] = v
+ }
+ }
+ return out
+}
http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/4df63f3a/traffic_stats/vendor/github.com/influxdata/influxdb/models/time.go
----------------------------------------------------------------------
diff --git a/traffic_stats/vendor/github.com/influxdata/influxdb/models/time.go b/traffic_stats/vendor/github.com/influxdata/influxdb/models/time.go
new file mode 100644
index 0000000..e98f2cb
--- /dev/null
+++ b/traffic_stats/vendor/github.com/influxdata/influxdb/models/time.go
@@ -0,0 +1,74 @@
+package models
+
+// Helper time methods since parsing time can easily overflow and we only support a
+// specific time range.
+
+import (
+ "fmt"
+ "math"
+ "time"
+)
+
+const (
+ // MinNanoTime is the minumum time that can be represented.
+ //
+ // 1677-09-21 00:12:43.145224194 +0000 UTC
+ //
+ // The two lowest minimum integers are used as sentinel values. The
+ // minimum value needs to be used as a value lower than any other value for
+ // comparisons and another separate value is needed to act as a sentinel
+ // default value that is unusable by the user, but usable internally.
+ // Because these two values need to be used for a special purpose, we do
+ // not allow users to write points at these two times.
+ MinNanoTime = int64(math.MinInt64) + 2
+
+ // MaxNanoTime is the maximum time that can be represented.
+ //
+ // 2262-04-11 23:47:16.854775806 +0000 UTC
+ //
+ // The highest time represented by a nanosecond needs to be used for an
+ // exclusive range in the shard group, so the maximum time needs to be one
+ // less than the possible maximum number of nanoseconds representable by an
+ // int64 so that we don't lose a point at that one time.
+ MaxNanoTime = int64(math.MaxInt64) - 1
+)
+
+var (
+ minNanoTime = time.Unix(0, MinNanoTime).UTC()
+ maxNanoTime = time.Unix(0, MaxNanoTime).UTC()
+
+ // ErrTimeOutOfRange gets returned when time is out of the representable range using int64 nanoseconds since the epoch.
+ ErrTimeOutOfRange = fmt.Errorf("time outside range %d - %d", MinNanoTime, MaxNanoTime)
+)
+
+// SafeCalcTime safely calculates the time given. Will return error if the time is outside the
+// supported range.
+func SafeCalcTime(timestamp int64, precision string) (time.Time, error) {
+ mult := GetPrecisionMultiplier(precision)
+ if t, ok := safeSignedMult(timestamp, mult); ok {
+ tme := time.Unix(0, t).UTC()
+ return tme, CheckTime(tme)
+ }
+
+ return time.Time{}, ErrTimeOutOfRange
+}
+
+// CheckTime checks that a time is within the safe range.
+func CheckTime(t time.Time) error {
+ if t.Before(minNanoTime) || t.After(maxNanoTime) {
+ return ErrTimeOutOfRange
+ }
+ return nil
+}
+
+// Perform the multiplication and check to make sure it didn't overflow.
+func safeSignedMult(a, b int64) (int64, bool) {
+ if a == 0 || b == 0 || a == 1 || b == 1 {
+ return a * b, true
+ }
+ if a == MinNanoTime || b == MaxNanoTime {
+ return 0, false
+ }
+ c := a * b
+ return c, c/b == a
+}
http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/4df63f3a/traffic_stats/vendor/github.com/influxdata/influxdb/pkg/escape/bytes.go
----------------------------------------------------------------------
diff --git a/traffic_stats/vendor/github.com/influxdata/influxdb/pkg/escape/bytes.go b/traffic_stats/vendor/github.com/influxdata/influxdb/pkg/escape/bytes.go
new file mode 100644
index 0000000..f148d66
--- /dev/null
+++ b/traffic_stats/vendor/github.com/influxdata/influxdb/pkg/escape/bytes.go
@@ -0,0 +1,111 @@
+// Package escape contains utilities for escaping parts of InfluxQL
+// and InfluxDB line protocol.
+package escape
+
+import (
+ "bytes"
+ "strings"
+)
+
+// Codes is a map of bytes to be escaped.
+var Codes = map[byte][]byte{
+ ',': []byte(`\,`),
+ '"': []byte(`\"`),
+ ' ': []byte(`\ `),
+ '=': []byte(`\=`),
+}
+
+// Bytes escapes characters on the input slice, as defined by Codes.
+func Bytes(in []byte) []byte {
+ for b, esc := range Codes {
+ in = bytes.Replace(in, []byte{b}, esc, -1)
+ }
+ return in
+}
+
+const escapeChars = `," =`
+
+// IsEscaped returns whether b has any escaped characters,
+// i.e. whether b seems to have been processed by Bytes.
+func IsEscaped(b []byte) bool {
+ for len(b) > 0 {
+ i := bytes.IndexByte(b, '\\')
+ if i < 0 {
+ return false
+ }
+
+ if i+1 < len(b) && strings.IndexByte(escapeChars, b[i+1]) >= 0 {
+ return true
+ }
+ b = b[i+1:]
+ }
+ return false
+}
+
+// AppendUnescaped appends the unescaped version of src to dst
+// and returns the resulting slice.
+func AppendUnescaped(dst, src []byte) []byte {
+ var pos int
+ for len(src) > 0 {
+ next := bytes.IndexByte(src[pos:], '\\')
+ if next < 0 || pos+next+1 >= len(src) {
+ return append(dst, src...)
+ }
+
+ if pos+next+1 < len(src) && strings.IndexByte(escapeChars, src[pos+next+1]) >= 0 {
+ if pos+next > 0 {
+ dst = append(dst, src[:pos+next]...)
+ }
+ src = src[pos+next+1:]
+ pos = 0
+ } else {
+ pos += next + 1
+ }
+ }
+
+ return dst
+}
+
+// Unescape returns a new slice containing the unescaped version of in.
+func Unescape(in []byte) []byte {
+ if len(in) == 0 {
+ return nil
+ }
+
+ if bytes.IndexByte(in, '\\') == -1 {
+ return in
+ }
+
+ i := 0
+ inLen := len(in)
+ var out []byte
+
+ for {
+ if i >= inLen {
+ break
+ }
+ if in[i] == '\\' && i+1 < inLen {
+ switch in[i+1] {
+ case ',':
+ out = append(out, ',')
+ i += 2
+ continue
+ case '"':
+ out = append(out, '"')
+ i += 2
+ continue
+ case ' ':
+ out = append(out, ' ')
+ i += 2
+ continue
+ case '=':
+ out = append(out, '=')
+ i += 2
+ continue
+ }
+ }
+ out = append(out, in[i])
+ i += 1
+ }
+ return out
+}
http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/4df63f3a/traffic_stats/vendor/github.com/influxdata/influxdb/pkg/escape/strings.go
----------------------------------------------------------------------
diff --git a/traffic_stats/vendor/github.com/influxdata/influxdb/pkg/escape/strings.go b/traffic_stats/vendor/github.com/influxdata/influxdb/pkg/escape/strings.go
new file mode 100644
index 0000000..db98033
--- /dev/null
+++ b/traffic_stats/vendor/github.com/influxdata/influxdb/pkg/escape/strings.go
@@ -0,0 +1,21 @@
+package escape
+
+import "strings"
+
+var (
+ escaper = strings.NewReplacer(`,`, `\,`, `"`, `\"`, ` `, `\ `, `=`, `\=`)
+ unescaper = strings.NewReplacer(`\,`, `,`, `\"`, `"`, `\ `, ` `, `\=`, `=`)
+)
+
+// UnescapeString returns unescaped version of in.
+func UnescapeString(in string) string {
+ if strings.IndexByte(in, '\\') == -1 {
+ return in
+ }
+ return unescaper.Replace(in)
+}
+
+// String returns the escaped version of in.
+func String(in string) string {
+ return escaper.Replace(in)
+}