forked from caict-benchmark/BDC-TS
-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathhttp_writer.go
More file actions
118 lines (99 loc) · 3.42 KB
/
Copy pathhttp_writer.go
File metadata and controls
118 lines (99 loc) · 3.42 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
package main
// This file lifted wholesale from mountainflux by Mark Rushakoff.
import (
"bytes"
"fmt"
"log"
"net/url"
"time"
"github.com/valyala/fasthttp"
)
const DefaultIdleConnectionTimeout = 90 * time.Second
var (
BackoffError error = fmt.Errorf("backpressure is needed")
backoffMagicWords0 []byte = []byte("engine: cache maximum memory size exceeded")
backoffMagicWords1 []byte = []byte("write failed: hinted handoff queue not empty")
backoffMagicWords2a []byte = []byte("write failed: read message type: read tcp")
backoffMagicWords2b []byte = []byte("i/o timeout")
backoffMagicWords3 []byte = []byte("write failed: engine: cache-max-memory-size exceeded")
backoffMagicWords4 []byte = []byte("timeout")
backoffMagicWords5 []byte = []byte("write failed: can not exceed max connections of 500")
)
// HTTPWriterConfig is the configuration used to create an HTTPWriter.
type HTTPWriterConfig struct {
// URL of the host, in form "http://example.com:8086"
Host string
// Name of the target database into which points will be written.
Database string
BackingOffChan chan bool
BackingOffDone chan struct{}
// Debug label for more informative errors.
DebugInfo string
}
// HTTPWriter is a Writer that writes to an InfluxDB HTTP server.
type HTTPWriter struct {
client fasthttp.Client
c HTTPWriterConfig
url []byte
}
// NewHTTPWriter returns a new HTTPWriter from the supplied HTTPWriterConfig.
func NewHTTPWriter(c HTTPWriterConfig, consistency string) *HTTPWriter {
return &HTTPWriter{
client: fasthttp.Client{
Name: "bulk_load_influx",
MaxIdleConnDuration: DefaultIdleConnectionTimeout,
},
c: c,
url: []byte(c.Host + "/write?consistency=" + consistency + "&db=" + url.QueryEscape(c.Database)),
}
}
var (
post = []byte("POST")
textPlain = []byte("text/plain")
)
// WriteLineProtocol writes the given byte slice to the HTTP server described in the Writer's HTTPWriterConfig.
// It returns the latency in nanoseconds and any error received while sending the data over HTTP,
// or it returns a new error if the HTTP response isn't as expected.
func (w *HTTPWriter) WriteLineProtocol(body []byte, isGzip bool) (int64, error) {
req := fasthttp.AcquireRequest()
req.Header.SetContentTypeBytes(textPlain)
req.Header.SetMethodBytes(post)
req.Header.SetRequestURIBytes(w.url)
if isGzip {
req.Header.Add("Content-Encoding", "gzip")
}
req.SetBody(body)
resp := fasthttp.AcquireResponse()
start := time.Now()
err := w.client.Do(req, resp)
lat := time.Since(start).Nanoseconds()
if err == nil {
sc := resp.StatusCode()
if sc == 500 && backpressurePred(resp.Body()) {
err = BackoffError
log.Printf("backoff suggested, reason: %s", resp.Body())
} else if sc != fasthttp.StatusNoContent {
err = fmt.Errorf("[DebugInfo: %s] Invalid write response (status %d): %s", w.c.DebugInfo, sc, resp.Body())
}
}
fasthttp.ReleaseResponse(resp)
fasthttp.ReleaseRequest(req)
return lat, err
}
func backpressurePred(body []byte) bool {
if bytes.Contains(body, backoffMagicWords0) {
return true
} else if bytes.Contains(body, backoffMagicWords1) {
return true
} else if bytes.Contains(body, backoffMagicWords2a) && bytes.Contains(body, backoffMagicWords2b) {
return true
} else if bytes.Contains(body, backoffMagicWords3) {
return true
} else if bytes.Contains(body, backoffMagicWords4) {
return true
} else if bytes.Contains(body, backoffMagicWords5) {
return true
} else {
return false
}
}