mirror of
https://github.com/VictoriaMetrics/VictoriaMetrics.git
synced 2026-06-08 03:14:09 +03:00
Compare commits
36 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7327adbc86 | ||
|
|
9f027ec176 | ||
|
|
cd53f7d177 | ||
|
|
d0d258b314 | ||
|
|
d88725f133 | ||
|
|
8dbf430469 | ||
|
|
9ef4d32a9a | ||
|
|
0d7505b00e | ||
|
|
2839f4688a | ||
|
|
605d588ba6 | ||
|
|
7483deccca | ||
|
|
893b62c682 | ||
|
|
7830c10eb2 | ||
|
|
e4f1bfd221 | ||
|
|
91ee1bce2e | ||
|
|
8b14572f70 | ||
|
|
8eaced8cae | ||
|
|
1585dab5a3 | ||
|
|
cd66d3fc43 | ||
|
|
ea231f8167 | ||
|
|
46bfdbe6cf | ||
|
|
4f0a645f77 | ||
|
|
b829fe5e39 | ||
|
|
164278151f | ||
|
|
c4632faa9d | ||
|
|
a768198814 | ||
|
|
57f4875024 | ||
|
|
b8038a14e7 | ||
|
|
f358fb72d1 | ||
|
|
1c436b2723 | ||
|
|
a973df6d79 | ||
|
|
d4132a6915 | ||
|
|
d5aeda0e1a | ||
|
|
bb71b6d47d | ||
|
|
fc71602039 | ||
|
|
c60fdbed30 |
30
README.md
30
README.md
@@ -6,7 +6,7 @@
|
||||
[](https://github.com/VictoriaMetrics/VictoriaMetrics/actions)
|
||||
[](https://codecov.io/gh/VictoriaMetrics/VictoriaMetrics)
|
||||
|
||||
<img alt="Victoria Metrics" src="logo.png" height="200px">
|
||||
<img alt="Victoria Metrics" src="logo.png">
|
||||
|
||||
## VictoriaMetrics
|
||||
|
||||
@@ -38,9 +38,11 @@ Cluster version is available [here](https://github.com/VictoriaMetrics/VictoriaM
|
||||
* High data compression, so [up to 70x more data points](https://medium.com/@valyala/when-size-matters-benchmarking-victoriametrics-vs-timescale-and-influxdb-6035811952d4)
|
||||
may be crammed into limited storage comparing to TimescaleDB.
|
||||
* Optimized for storage with high-latency IO and low IOPS (HDD and network storage in AWS, Google Cloud, Microsoft Azure, etc). See [graphs from these benchmarks](https://medium.com/@valyala/high-cardinality-tsdb-benchmarks-victoriametrics-vs-timescaledb-vs-influxdb-13e6ee64dd6b).
|
||||
* A single-node VictoriaMetrics may substitute moderately sized clusters built with competing solutions such as Thanos, Uber M3, Cortex, InfluxDB or TimescaleDB.
|
||||
See [vertical scalability benchmarks](https://medium.com/@valyala/measuring-vertical-scalability-for-time-series-databases-in-google-cloud-92550d78d8ae)
|
||||
and [comparing Thanos to VictoriaMetrics cluster](https://medium.com/@valyala/comparing-thanos-to-victoriametrics-cluster-b193bea1683).
|
||||
* A single-node VictoriaMetrics may substitute moderately sized clusters built with competing solutions such as Thanos, M3DB, Cortex, InfluxDB or TimescaleDB.
|
||||
See [vertical scalability benchmarks](https://medium.com/@valyala/measuring-vertical-scalability-for-time-series-databases-in-google-cloud-92550d78d8ae),
|
||||
[comparing Thanos to VictoriaMetrics cluster](https://medium.com/@valyala/comparing-thanos-to-victoriametrics-cluster-b193bea1683)
|
||||
and [Remote Write Storage Wars](https://promcon.io/2019-munich/talks/remote-write-storage-wars/) talk
|
||||
from [PromCon 2019](https://promcon.io/2019-munich/talks/remote-write-storage-wars/).
|
||||
* Easy operation:
|
||||
* VictoriaMetrics consists of a single [small executable](https://medium.com/@valyala/stripping-dependency-bloat-in-victoriametrics-docker-image-983fb5912b0d) without external dependencies.
|
||||
* All the configuration is done via explicit command-line flags with reasonable defaults.
|
||||
@@ -501,6 +503,7 @@ Read [these instructions](https://github.com/VictoriaMetrics/VictoriaMetrics/iss
|
||||
### Third-party contributions
|
||||
|
||||
* [Unofficial yum repository](https://copr.fedorainfracloud.org/coprs/antonpatsev/VictoriaMetrics/) ([source code](https://github.com/patsevanton/victoriametrics-rpm))
|
||||
* [Prometheus -> VictoriaMetrics exporter](https://github.com/ryotarai/prometheus-tsdb-dump)
|
||||
|
||||
|
||||
### How to work with snapshots?
|
||||
@@ -625,7 +628,7 @@ A rough estimation of the required resources for ingestion path:
|
||||
* RAM size: less than 1KB per active time series. So, ~1GB of RAM is required for 1M active time series.
|
||||
Time series is considered active if new data points have been added to it recently or if it has been recently queried.
|
||||
The number of active time series may be obtained from `vm_cache_entries{type="storage/hour_metric_ids"}` metric
|
||||
exproted on the `/metrics` page.
|
||||
exported on the `/metrics` page.
|
||||
VictoriaMetrics stores various caches in RAM. Memory size for these caches may be limited by `-memory.allowedPercent` flag.
|
||||
|
||||
* CPU cores: a CPU core per 300K inserted data points per second. So, ~4 CPU cores are required for processing
|
||||
@@ -706,7 +709,7 @@ There is no downsampling support at the moment, but:
|
||||
- VictoriaMetrics has good compression for on-disk data. See [this article](https://medium.com/@valyala/victoriametrics-achieving-better-compression-for-time-series-data-than-gorilla-317bc1f95932)
|
||||
for details.
|
||||
|
||||
These properties reduce the need in downsampling. We plan to implement downsampling in the future.
|
||||
These properties reduce the need of downsampling. We plan to implement downsampling in the future.
|
||||
See [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/36) for details.
|
||||
|
||||
|
||||
@@ -751,14 +754,14 @@ For example, substitute `-graphiteListenAddr=:2003` with `-graphiteListenAddr=<i
|
||||
|
||||
### Tuning
|
||||
|
||||
* There is no need in VictoriaMetrics tuning since it uses reasonable defaults for command-line flags,
|
||||
* There is no need for VictoriaMetrics tuning since it uses reasonable defaults for command-line flags,
|
||||
which are automatically adjusted for the available CPU and RAM resources.
|
||||
* There is no need in Operating System tuning since VictoriaMetrics is optimized for default OS settings.
|
||||
* There is no need for Operating System tuning since VictoriaMetrics is optimized for default OS settings.
|
||||
The only option is increasing the limit on [the number of open files in the OS](https://medium.com/@muhammadtriwibowo/set-permanently-ulimit-n-open-files-in-ubuntu-4d61064429a),
|
||||
so Prometheus instances could establish more connections to VictoriaMetrics.
|
||||
* The recommended filesystem is `ext4`, the recommended persistent storage is [persistent HDD-based disk on GCP](https://cloud.google.com/compute/docs/disks/#pdspecs),
|
||||
since it is protected from hardware failures via internal replication and it can be [resized on the fly](https://cloud.google.com/compute/docs/disks/add-persistent-disk#resize_pd).
|
||||
If you plan storing more than 1TB of data on `ext4` partition or plan extending it to more than 16TB,
|
||||
If you plan to store more than 1TB of data on `ext4` partition or plan extending it to more than 16TB,
|
||||
then the following options are recommended to pass to `mkfs.ext4`:
|
||||
|
||||
```
|
||||
@@ -789,7 +792,7 @@ The most interesting metrics are:
|
||||
### Troubleshooting
|
||||
|
||||
* It is recommended to use default command-line flag values (i.e. don't set them explicitly) until the need
|
||||
in tweaking these flag values arises.
|
||||
of tweaking these flag values arises.
|
||||
|
||||
* If VictoriaMetrics works slowly and eats more than a CPU core per 100K ingested data points per second,
|
||||
then it is likely you have too many active time series for the current amount of RAM.
|
||||
@@ -803,7 +806,7 @@ The most interesting metrics are:
|
||||
has at least 20% of free space comparing to disk size.
|
||||
|
||||
* If VictoriaMetrics doesn't work because of certain parts are corrupted due to disk errors,
|
||||
then just remove directoreis with broken parts. This will recover VictoriaMetrics at the cost
|
||||
then just remove directories with broken parts. This will recover VictoriaMetrics at the cost
|
||||
of data loss stored in the broken parts. In the future, `vmrecover` tool will be created
|
||||
for automatic recovering from such errors.
|
||||
|
||||
@@ -854,7 +857,7 @@ The collected profiles may be analyzed with [go tool pprof](https://github.com/g
|
||||
- [ ] CLI tool for data migration, re-balancing and adding/removing nodes [#103](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/103)
|
||||
|
||||
|
||||
The discussion happens [here](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/129). Feel free to comment any item or add own one.
|
||||
The discussion happens [here](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/129). Feel free to comment on any item or add you own one.
|
||||
|
||||
|
||||
## Contacts
|
||||
@@ -867,6 +870,7 @@ Contact us with any questions regarding VictoriaMetrics at [info@victoriametrics
|
||||
Feel free asking any questions regarding VictoriaMetrics:
|
||||
|
||||
- [slack](http://slack.victoriametrics.com/)
|
||||
- [reddit](https://www.reddit.com/r/VictoriaMetrics/)
|
||||
- [telegram-en](https://t.me/VictoriaMetrics_en)
|
||||
- [telegram-ru](https://t.me/VictoriaMetrics_ru1)
|
||||
- [google groups](https://groups.google.com/forum/#!forum/victorametrics-users)
|
||||
@@ -897,7 +901,7 @@ Report bugs and propose new features [here](https://github.com/VictoriaMetrics/V
|
||||
|
||||
## Victoria Metrics Logo
|
||||
|
||||
[Zip](VM_logo.zip) contains three folders with different image orientation (main color and inverted version).
|
||||
[Zip](VM_logo.zip) contains three folders with different image orientations (main color and inverted version).
|
||||
|
||||
Files included in each folder:
|
||||
|
||||
|
||||
@@ -13,11 +13,8 @@
|
||||
"data":{"resultType":"matrix",
|
||||
"result":[{"metric":{"__name__":"max_lookback_set"},"values":[
|
||||
["{TIME_S-150s}","4"],
|
||||
["{TIME_S-140s}","4"],
|
||||
["{TIME_S-120s}","3"],
|
||||
["{TIME_S-110s}","3"],
|
||||
["{TIME_S-60s}","2"],
|
||||
["{TIME_S-50s}","2"],
|
||||
["{TIME_S-30s}","1"],
|
||||
["{TIME_S-20s}","1"]
|
||||
]}]}}
|
||||
|
||||
@@ -19,14 +19,12 @@
|
||||
["{TIME_S-110s}","3"],
|
||||
["{TIME_S-100s}","3"],
|
||||
["{TIME_S-90s}","3"],
|
||||
["{TIME_S-80s}","3"],
|
||||
["{TIME_S-70s}","3"],
|
||||
["{TIME_S-60s}","2"],
|
||||
["{TIME_S-50s}","2"],
|
||||
["{TIME_S-40s}","2"],
|
||||
["{TIME_S-30s}","1"],
|
||||
["{TIME_S-20s}","1"],
|
||||
["{TIME_S-10s}","1"],
|
||||
["{TIME_S}","1"]
|
||||
["{TIME_S-0s}","1"]
|
||||
]}]}}
|
||||
}
|
||||
|
||||
@@ -12,17 +12,14 @@ import (
|
||||
"github.com/VictoriaMetrics/metrics"
|
||||
)
|
||||
|
||||
var maxConcurrentInserts = flag.Int("maxConcurrentInserts", runtime.GOMAXPROCS(-1)*4, "The maximum number of concurrent inserts")
|
||||
|
||||
var (
|
||||
// ch is the channel for limiting concurrent calls to Do.
|
||||
ch chan struct{}
|
||||
|
||||
// waitDuration is the amount of time to wait until at least a single
|
||||
// concurrent Do call out of cap(ch) inserts is complete.
|
||||
waitDuration = time.Second * 30
|
||||
maxConcurrentInserts = flag.Int("maxConcurrentInserts", runtime.GOMAXPROCS(-1)*4, "The maximum number of concurrent inserts; see also `-insert.maxQueueDuration`")
|
||||
maxQueueDuration = flag.Duration("insert.maxQueueDuration", 30*time.Second, "The maximum duration for waiting in the queue for insert requests due to `-maxConcurrentInserts`")
|
||||
)
|
||||
|
||||
// ch is the channel for limiting concurrent calls to Do.
|
||||
var ch chan struct{}
|
||||
|
||||
// Init initializes concurrencylimiter.
|
||||
//
|
||||
// Init must be called after flag.Parse call.
|
||||
@@ -43,9 +40,9 @@ func Do(f func() error) error {
|
||||
}
|
||||
|
||||
// All the workers are busy.
|
||||
// Sleep for up to waitDuration.
|
||||
// Sleep for up to *maxQueueDuration.
|
||||
concurrencyLimitReached.Inc()
|
||||
t := timerpool.Get(waitDuration)
|
||||
t := timerpool.Get(*maxQueueDuration)
|
||||
select {
|
||||
case ch <- struct{}{}:
|
||||
timerpool.Put(t)
|
||||
@@ -56,7 +53,9 @@ func Do(f func() error) error {
|
||||
timerpool.Put(t)
|
||||
concurrencyLimitTimeout.Inc()
|
||||
return &httpserver.ErrorWithStatusCode{
|
||||
Err: fmt.Errorf("the server is overloaded with %d concurrent inserts; either increase -maxConcurrentInserts or reduce the load", cap(ch)),
|
||||
Err: fmt.Errorf("cannot handle more than %d concurrent inserts during %s; possible solutions: "+
|
||||
"increase `-insert.maxQueueDuration`, increase `-maxConcurrentInserts`, "+
|
||||
"decrease `-search.maxConcurrentRequests`, increase server capacity", *maxConcurrentInserts, *maxQueueDuration),
|
||||
StatusCode: http.StatusServiceUnavailable,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,7 +24,6 @@ var (
|
||||
"Telnet put messages and HTTP /api/put messages are simultaneously served on TCP port. "+
|
||||
"Usually :4242 must be set. Doesn't work if empty")
|
||||
opentsdbHTTPListenAddr = flag.String("opentsdbHTTPListenAddr", "", "TCP address to listen for OpentTSDB HTTP put requests. Usually :4242 must be set. Doesn't work if empty")
|
||||
maxInsertRequestSize = flag.Int("maxInsertRequestSize", 32*1024*1024, "The maximum size of a single insert request in bytes")
|
||||
maxLabelsPerTimeseries = flag.Int("maxLabelsPerTimeseries", 30, "The maximum number of labels accepted per time series. Superflouos labels are dropped")
|
||||
)
|
||||
|
||||
@@ -43,10 +42,10 @@ func Init() {
|
||||
graphiteServer = graphite.MustStart(*graphiteListenAddr)
|
||||
}
|
||||
if len(*opentsdbListenAddr) > 0 {
|
||||
opentsdbServer = opentsdb.MustStart(*opentsdbListenAddr, int64(*maxInsertRequestSize))
|
||||
opentsdbServer = opentsdb.MustStart(*opentsdbListenAddr)
|
||||
}
|
||||
if len(*opentsdbHTTPListenAddr) > 0 {
|
||||
opentsdbhttpServer = opentsdbhttp.MustStart(*opentsdbHTTPListenAddr, int64(*maxInsertRequestSize))
|
||||
opentsdbhttpServer = opentsdbhttp.MustStart(*opentsdbHTTPListenAddr)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -69,7 +68,7 @@ func RequestHandler(w http.ResponseWriter, r *http.Request) bool {
|
||||
switch path {
|
||||
case "/api/v1/write":
|
||||
prometheusWriteRequests.Inc()
|
||||
if err := prometheus.InsertHandler(r, int64(*maxInsertRequestSize)); err != nil {
|
||||
if err := prometheus.InsertHandler(r); err != nil {
|
||||
prometheusWriteErrors.Inc()
|
||||
httpserver.Errorf(w, "error in %q: %s", r.URL.Path, err)
|
||||
return true
|
||||
|
||||
@@ -36,7 +36,7 @@ type Server struct {
|
||||
// MustStart starts OpenTSDB collector on the given addr.
|
||||
//
|
||||
// MustStop must be called on the returned server when it is no longer needed.
|
||||
func MustStart(addr string, maxRequestSize int64) *Server {
|
||||
func MustStart(addr string) *Server {
|
||||
logger.Infof("starting TCP OpenTSDB collector at %q", addr)
|
||||
lnTCP, err := netutil.NewTCPListener("opentsdb", addr)
|
||||
if err != nil {
|
||||
@@ -45,7 +45,7 @@ func MustStart(addr string, maxRequestSize int64) *Server {
|
||||
ls := newListenerSwitch(lnTCP)
|
||||
lnHTTP := ls.newHTTPListener()
|
||||
lnTelnet := ls.newTelnetListener()
|
||||
httpServer := opentsdbhttp.MustServe(lnHTTP, maxRequestSize)
|
||||
httpServer := opentsdbhttp.MustServe(lnHTTP)
|
||||
|
||||
logger.Infof("starting UDP OpenTSDB collector at %q", addr)
|
||||
lnUDP, err := net.ListenPacket("udp4", addr)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package opentsdbhttp
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
@@ -15,6 +16,8 @@ import (
|
||||
"github.com/valyala/fastjson"
|
||||
)
|
||||
|
||||
var maxInsertRequestSize = flag.Int("opentsdbhttp.maxInsertRequestSize", 32*1024*1024, "The maximum size of OpenTSDB HTTP put request")
|
||||
|
||||
var (
|
||||
rowsInserted = metrics.NewCounter(`vm_rows_inserted_total{type="opentsdb-http"}`)
|
||||
rowsPerInsert = metrics.NewSummary(`vm_rows_per_insert{type="opentsdb-http"}`)
|
||||
@@ -26,13 +29,13 @@ var (
|
||||
|
||||
// insertHandler processes HTTP OpenTSDB put requests.
|
||||
// See http://opentsdb.net/docs/build/html/api_http/put.html
|
||||
func insertHandler(req *http.Request, maxSize int64) error {
|
||||
func insertHandler(req *http.Request) error {
|
||||
return concurrencylimiter.Do(func() error {
|
||||
return insertHandlerInternal(req, maxSize)
|
||||
return insertHandlerInternal(req)
|
||||
})
|
||||
}
|
||||
|
||||
func insertHandlerInternal(req *http.Request, maxSize int64) error {
|
||||
func insertHandlerInternal(req *http.Request) error {
|
||||
readCalls.Inc()
|
||||
|
||||
r := req.Body
|
||||
@@ -50,15 +53,15 @@ func insertHandlerInternal(req *http.Request, maxSize int64) error {
|
||||
defer putPushCtx(ctx)
|
||||
|
||||
// Read the request in ctx.reqBuf
|
||||
lr := io.LimitReader(r, maxSize+1)
|
||||
lr := io.LimitReader(r, int64(*maxInsertRequestSize)+1)
|
||||
reqLen, err := ctx.reqBuf.ReadFrom(lr)
|
||||
if err != nil {
|
||||
readErrors.Inc()
|
||||
return fmt.Errorf("cannot read HTTP OpenTSDB request: %s", err)
|
||||
}
|
||||
if reqLen > maxSize {
|
||||
if reqLen > int64(*maxInsertRequestSize) {
|
||||
readErrors.Inc()
|
||||
return fmt.Errorf("too big HTTP OpenTSDB request; mustn't exceed %d bytes", maxSize)
|
||||
return fmt.Errorf("too big HTTP OpenTSDB request; mustn't exceed `-opentsdbhttp.maxInsertRequestSize=%d` bytes", *maxInsertRequestSize)
|
||||
}
|
||||
|
||||
// Unmarshal the request to ctx.Rows
|
||||
|
||||
@@ -28,20 +28,20 @@ type Server struct {
|
||||
// MustStart starts HTTP OpenTSDB server on the given addr.
|
||||
//
|
||||
// MustStop must be called on the returned server when it is no longer needed.
|
||||
func MustStart(addr string, maxRequestSize int64) *Server {
|
||||
func MustStart(addr string) *Server {
|
||||
logger.Infof("starting HTTP OpenTSDB server at %q", addr)
|
||||
lnTCP, err := netutil.NewTCPListener("opentsdbhttp", addr)
|
||||
if err != nil {
|
||||
logger.Fatalf("cannot start HTTP OpenTSDB collector at %q: %s", addr, err)
|
||||
}
|
||||
return MustServe(lnTCP, maxRequestSize)
|
||||
return MustServe(lnTCP)
|
||||
}
|
||||
|
||||
// MustServe serves OpenTSDB HTTP put requests from ln with up to maxRequestSize size.
|
||||
// MustServe serves OpenTSDB HTTP put requests from ln.
|
||||
//
|
||||
// MustStop must be called on the returned server when it is no longer needed.
|
||||
func MustServe(ln net.Listener, maxRequestSize int64) *Server {
|
||||
h := newRequestHandler(maxRequestSize)
|
||||
func MustServe(ln net.Listener) *Server {
|
||||
h := newRequestHandler()
|
||||
hs := &http.Server{
|
||||
Handler: h,
|
||||
ReadTimeout: 30 * time.Second,
|
||||
@@ -82,12 +82,12 @@ func (s *Server) MustStop() {
|
||||
logger.Infof("OpenTSDB HTTP server at %q has been stopped", s.ln.Addr())
|
||||
}
|
||||
|
||||
func newRequestHandler(maxRequestSize int64) http.Handler {
|
||||
func newRequestHandler() http.Handler {
|
||||
rh := func(w http.ResponseWriter, r *http.Request) {
|
||||
switch r.URL.Path {
|
||||
case "/api/put":
|
||||
writeRequests.Inc()
|
||||
if err := insertHandler(r, maxRequestSize); err != nil {
|
||||
if err := insertHandler(r); err != nil {
|
||||
writeErrors.Inc()
|
||||
httpserver.Errorf(w, "error in %q: %s", r.URL.Path, err)
|
||||
return
|
||||
|
||||
@@ -18,16 +18,16 @@ var (
|
||||
)
|
||||
|
||||
// InsertHandler processes remote write for prometheus.
|
||||
func InsertHandler(r *http.Request, maxSize int64) error {
|
||||
func InsertHandler(r *http.Request) error {
|
||||
return concurrencylimiter.Do(func() error {
|
||||
return insertHandlerInternal(r, maxSize)
|
||||
return insertHandlerInternal(r)
|
||||
})
|
||||
}
|
||||
|
||||
func insertHandlerInternal(r *http.Request, maxSize int64) error {
|
||||
func insertHandlerInternal(r *http.Request) error {
|
||||
ctx := getPushCtx()
|
||||
defer putPushCtx(ctx)
|
||||
if err := ctx.Read(r, maxSize); err != nil {
|
||||
if err := ctx.Read(r); err != nil {
|
||||
return err
|
||||
}
|
||||
timeseries := ctx.req.Timeseries
|
||||
@@ -65,11 +65,11 @@ func (ctx *pushCtx) reset() {
|
||||
ctx.reqBuf = ctx.reqBuf[:0]
|
||||
}
|
||||
|
||||
func (ctx *pushCtx) Read(r *http.Request, maxSize int64) error {
|
||||
func (ctx *pushCtx) Read(r *http.Request) error {
|
||||
prometheusReadCalls.Inc()
|
||||
|
||||
var err error
|
||||
ctx.reqBuf, err = prompb.ReadSnappy(ctx.reqBuf[:0], r.Body, maxSize)
|
||||
ctx.reqBuf, err = prompb.ReadSnappy(ctx.reqBuf[:0], r.Body)
|
||||
if err != nil {
|
||||
prometheusReadErrors.Inc()
|
||||
return fmt.Errorf("cannot read prompb.WriteRequest: %s", err)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package vmimport
|
||||
|
||||
import (
|
||||
"math"
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
@@ -101,6 +102,18 @@ func TestRowsUnmarshalSuccess(t *testing.T) {
|
||||
}},
|
||||
})
|
||||
|
||||
// Inf and nan values
|
||||
f(`{"metric":{"foo":"bar"},"values":[Inf, -Inf],"timestamps":[456, 789]}`, &Rows{
|
||||
Rows: []Row{{
|
||||
Tags: []Tag{{
|
||||
Key: []byte("foo"),
|
||||
Value: []byte("bar"),
|
||||
}},
|
||||
Values: []float64{math.Inf(1), math.Inf(-1)},
|
||||
Timestamps: []int64{456, 789},
|
||||
}},
|
||||
})
|
||||
|
||||
// Line with multiple tags
|
||||
f(`{"metric":{"foo":"bar","baz":"xx"},"values":[1.23, -3.21],"timestamps" : [456,789]}`, &Rows{
|
||||
Rows: []Row{{
|
||||
|
||||
@@ -16,8 +16,9 @@ var (
|
||||
"Example: gcs://bucket/path/to/backup/dir, s3://bucket/path/to/backup/dir or fs:///path/to/local/backup/dir")
|
||||
storageDataPath = flag.String("storageDataPath", "victoria-metrics-data", "Destination path where backup must be restored. "+
|
||||
"VictoriaMetrics must be stopped when restoring from backup. -storageDataPath dir can be non-empty. In this case only missing data is downloaded from backup")
|
||||
concurrency = flag.Int("concurrency", 10, "The number of concurrent workers. Higher concurrency may reduce restore duration")
|
||||
maxBytesPerSecond = flag.Int("maxBytesPerSecond", 0, "The maximum download speed. There is no limit if it is set to 0")
|
||||
concurrency = flag.Int("concurrency", 10, "The number of concurrent workers. Higher concurrency may reduce restore duration")
|
||||
maxBytesPerSecond = flag.Int("maxBytesPerSecond", 0, "The maximum download speed. There is no limit if it is set to 0")
|
||||
skipBackupCompleteCheck = flag.Bool("skipBackupCompleteCheck", false, "Whether to skip checking for `backup complete` file in `-src`. This may be useful for restoring from old backups, which were created without `backup complete` file")
|
||||
)
|
||||
|
||||
func main() {
|
||||
@@ -34,9 +35,10 @@ func main() {
|
||||
logger.Fatalf("%s", err)
|
||||
}
|
||||
a := &actions.Restore{
|
||||
Concurrency: *concurrency,
|
||||
Src: srcFS,
|
||||
Dst: dstFS,
|
||||
Concurrency: *concurrency,
|
||||
Src: srcFS,
|
||||
Dst: dstFS,
|
||||
SkipBackupCompleteCheck: *skipBackupCompleteCheck,
|
||||
}
|
||||
if err := a.Run(); err != nil {
|
||||
logger.Fatalf("cannot restore from backup: %s", err)
|
||||
|
||||
@@ -21,10 +21,25 @@ import (
|
||||
|
||||
var (
|
||||
deleteAuthKey = flag.String("deleteAuthKey", "", "authKey for metrics' deletion via /api/v1/admin/tsdb/delete_series")
|
||||
maxConcurrentRequests = flag.Int("search.maxConcurrentRequests", runtime.GOMAXPROCS(-1)*2, "The maximum number of concurrent search requests. It shouldn't exceed 2*vCPUs for better performance. See also -search.maxQueueDuration")
|
||||
maxQueueDuration = flag.Duration("search.maxQueueDuration", 10*time.Second, "The maximum time the request waits for execution when -search.maxConcurrentRequests limit is reached")
|
||||
maxConcurrentRequests = flag.Int("search.maxConcurrentRequests", getDefaultMaxConcurrentRequests(), "The maximum number of concurrent search requests. "+
|
||||
"It shouldn't be high, since a single request can saturate all the CPU cores. See also `-search.maxQueueDuration`")
|
||||
maxQueueDuration = flag.Duration("search.maxQueueDuration", 10*time.Second, "The maximum time the request waits for execution when `-search.maxConcurrentRequests` limit is reached")
|
||||
)
|
||||
|
||||
func getDefaultMaxConcurrentRequests() int {
|
||||
n := runtime.GOMAXPROCS(-1)
|
||||
if n <= 4 {
|
||||
n *= 2
|
||||
}
|
||||
if n > 16 {
|
||||
// A single request can saturate all the CPU cores, so there is no sense
|
||||
// in allowing higher number of concurrent requests - they will just contend
|
||||
// for unavailable CPU time.
|
||||
n = 16
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
// Init initializes vmselect
|
||||
func Init() {
|
||||
tmpDirPath := *vmstorage.DataPath + "/tmp"
|
||||
@@ -72,7 +87,9 @@ func RequestHandler(w http.ResponseWriter, r *http.Request) bool {
|
||||
timerpool.Put(t)
|
||||
concurrencyLimitTimeout.Inc()
|
||||
err := &httpserver.ErrorWithStatusCode{
|
||||
Err: fmt.Errorf("cannot handle more than %d concurrent requests", cap(concurrencyCh)),
|
||||
Err: fmt.Errorf("cannot handle more than %d concurrent search requests during %s; possible solutions: "+
|
||||
"increase `-search.maxQueueDuration`, increase `-search.maxConcurrentRequests`, increase server capacity",
|
||||
*maxConcurrentRequests, *maxQueueDuration),
|
||||
StatusCode: http.StatusServiceUnavailable,
|
||||
}
|
||||
httpserver.Errorf(w, "%s", err)
|
||||
|
||||
@@ -36,6 +36,9 @@ func maxInmemoryTmpBlocksFile() int {
|
||||
if maxLen < 64*1024 {
|
||||
return 64 * 1024
|
||||
}
|
||||
if maxLen > 4*1024*1024 {
|
||||
return 4*1024*1024
|
||||
}
|
||||
return maxLen
|
||||
}
|
||||
|
||||
|
||||
@@ -560,7 +560,7 @@ func QueryHandler(w http.ResponseWriter, r *http.Request) error {
|
||||
}
|
||||
|
||||
if len(query) > *maxQueryLen {
|
||||
return fmt.Errorf(`too long query; got %d bytes; mustn't exceed %d bytes`, len(query), *maxQueryLen)
|
||||
return fmt.Errorf("too long query; got %d bytes; mustn't exceed `-search.maxQueryLen=%d` bytes", len(query), *maxQueryLen)
|
||||
}
|
||||
if !getBool(r, "nocache") && ct-start < queryOffset {
|
||||
// Adjust start time only if `nocache` arg isn't set.
|
||||
@@ -685,7 +685,7 @@ func queryRangeHandler(w http.ResponseWriter, query string, start, end, step int
|
||||
|
||||
// Validate input args.
|
||||
if len(query) > *maxQueryLen {
|
||||
return fmt.Errorf(`too long query; got %d bytes; mustn't exceed %d bytes`, len(query), *maxQueryLen)
|
||||
return fmt.Errorf("too long query; got %d bytes; mustn't exceed `-search.maxQueryLen=%d` bytes", len(query), *maxQueryLen)
|
||||
}
|
||||
if start > end {
|
||||
end = start + defaultStep
|
||||
|
||||
@@ -323,6 +323,10 @@ func tryGetArgRollupFuncWithMetricExpr(ae *metricsql.AggrFuncExpr) (*metricsql.F
|
||||
return nil, nil
|
||||
}
|
||||
rollupArgIdx := getRollupArgIdx(fe.Name)
|
||||
if rollupArgIdx >= len(fe.Args) {
|
||||
// Incorrect number of args for rollup func.
|
||||
return nil, nil
|
||||
}
|
||||
arg := fe.Args[rollupArgIdx]
|
||||
if me, ok := arg.(*metricsql.MetricExpr); ok {
|
||||
if me.IsEmpty() {
|
||||
@@ -359,6 +363,9 @@ func evalExprs(ec *EvalConfig, es []metricsql.Expr) ([][]*timeseries, error) {
|
||||
func evalRollupFuncArgs(ec *EvalConfig, fe *metricsql.FuncExpr) ([]interface{}, *metricsql.RollupExpr, error) {
|
||||
var re *metricsql.RollupExpr
|
||||
rollupArgIdx := getRollupArgIdx(fe.Name)
|
||||
if len(fe.Args) <= rollupArgIdx {
|
||||
return nil, nil, fmt.Errorf("expecting at least %d args to %q; got %d args; expr: %q", rollupArgIdx+1, fe.Name, len(fe.Args), fe.AppendString(nil))
|
||||
}
|
||||
args := make([]interface{}, len(fe.Args))
|
||||
for i, arg := range fe.Args {
|
||||
if i == rollupArgIdx {
|
||||
@@ -430,7 +437,7 @@ func evalRollupFunc(ec *EvalConfig, name string, rf rollupFunc, expr metricsql.E
|
||||
if iafc != nil {
|
||||
logger.Panicf("BUG: iafc must be nil for rollup %q over subquery %q", name, re.AppendString(nil))
|
||||
}
|
||||
rvs, err = evalRollupFuncWithSubquery(ecNew, name, rf, re)
|
||||
rvs, err = evalRollupFuncWithSubquery(ecNew, name, rf, expr, re)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -449,7 +456,7 @@ func evalRollupFunc(ec *EvalConfig, name string, rf rollupFunc, expr metricsql.E
|
||||
return rvs, nil
|
||||
}
|
||||
|
||||
func evalRollupFuncWithSubquery(ec *EvalConfig, name string, rf rollupFunc, re *metricsql.RollupExpr) ([]*timeseries, error) {
|
||||
func evalRollupFuncWithSubquery(ec *EvalConfig, name string, rf rollupFunc, expr metricsql.Expr, re *metricsql.RollupExpr) ([]*timeseries, error) {
|
||||
// TODO: determine whether to use rollupResultCacheV here.
|
||||
var step int64
|
||||
if len(re.Step) > 0 {
|
||||
@@ -490,7 +497,10 @@ func evalRollupFuncWithSubquery(ec *EvalConfig, name string, rf rollupFunc, re *
|
||||
}
|
||||
|
||||
sharedTimestamps := getTimestamps(ec.Start, ec.End, ec.Step)
|
||||
preFunc, rcs := getRollupConfigs(name, rf, ec.Start, ec.End, ec.Step, window, ec.LookbackDelta, sharedTimestamps)
|
||||
preFunc, rcs, err := getRollupConfigs(name, rf, expr, ec.Start, ec.End, ec.Step, window, ec.LookbackDelta, sharedTimestamps)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tss := make([]*timeseries, 0, len(tssSQ)*len(rcs))
|
||||
var tssLock sync.Mutex
|
||||
removeMetricGroup := !rollupFuncsKeepMetricGroup[name]
|
||||
@@ -599,6 +609,14 @@ func evalRollupFuncWithMetricExpr(ec *EvalConfig, name string, rf rollupFunc,
|
||||
rollupResultCacheMiss.Inc()
|
||||
}
|
||||
|
||||
// Obtain rollup configs before fetching data from db,
|
||||
// so type errors can be caught earlier.
|
||||
sharedTimestamps := getTimestamps(start, ec.End, ec.Step)
|
||||
preFunc, rcs, err := getRollupConfigs(name, rf, expr, start, ec.End, ec.Step, window, ec.LookbackDelta, sharedTimestamps)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Fetch the remaining part of the result.
|
||||
tfs := toTagFilters(me.LabelFilters)
|
||||
sq := &storage.SearchQuery{
|
||||
@@ -623,8 +641,6 @@ func evalRollupFuncWithMetricExpr(ec *EvalConfig, name string, rf rollupFunc,
|
||||
tss = mergeTimeseries(tssCached, tss, start, ec)
|
||||
return tss, nil
|
||||
}
|
||||
sharedTimestamps := getTimestamps(start, ec.End, ec.Step)
|
||||
preFunc, rcs := getRollupConfigs(name, rf, start, ec.End, ec.Step, window, ec.LookbackDelta, sharedTimestamps)
|
||||
|
||||
// Verify timeseries fit available memory after the rollup.
|
||||
// Take into account points from tssCached.
|
||||
@@ -751,62 +767,6 @@ func doRollupForTimeseries(rc *rollupConfig, tsDst *timeseries, mnSrc *storage.M
|
||||
tsDst.denyReuse = true
|
||||
}
|
||||
|
||||
func getRollupConfigs(name string, rf rollupFunc, start, end, step, window int64, lookbackDelta int64, sharedTimestamps []int64) (
|
||||
func(values []float64, timestamps []int64), []*rollupConfig) {
|
||||
preFunc := func(values []float64, timestamps []int64) {}
|
||||
if rollupFuncsRemoveCounterResets[name] {
|
||||
preFunc = func(values []float64, timestamps []int64) {
|
||||
removeCounterResets(values)
|
||||
}
|
||||
}
|
||||
newRollupConfig := func(rf rollupFunc, tagValue string) *rollupConfig {
|
||||
return &rollupConfig{
|
||||
TagValue: tagValue,
|
||||
Func: rf,
|
||||
Start: start,
|
||||
End: end,
|
||||
Step: step,
|
||||
Window: window,
|
||||
MayAdjustWindow: rollupFuncsMayAdjustWindow[name],
|
||||
LookbackDelta: lookbackDelta,
|
||||
Timestamps: sharedTimestamps,
|
||||
}
|
||||
}
|
||||
appendRollupConfigs := func(dst []*rollupConfig) []*rollupConfig {
|
||||
dst = append(dst, newRollupConfig(rollupMin, "min"))
|
||||
dst = append(dst, newRollupConfig(rollupMax, "max"))
|
||||
dst = append(dst, newRollupConfig(rollupAvg, "avg"))
|
||||
return dst
|
||||
}
|
||||
var rcs []*rollupConfig
|
||||
switch name {
|
||||
case "rollup":
|
||||
rcs = appendRollupConfigs(rcs)
|
||||
case "rollup_rate", "rollup_deriv":
|
||||
preFuncPrev := preFunc
|
||||
preFunc = func(values []float64, timestamps []int64) {
|
||||
preFuncPrev(values, timestamps)
|
||||
derivValues(values, timestamps)
|
||||
}
|
||||
rcs = appendRollupConfigs(rcs)
|
||||
case "rollup_increase", "rollup_delta":
|
||||
preFuncPrev := preFunc
|
||||
preFunc = func(values []float64, timestamps []int64) {
|
||||
preFuncPrev(values, timestamps)
|
||||
deltaValues(values)
|
||||
}
|
||||
rcs = appendRollupConfigs(rcs)
|
||||
case "rollup_candlestick":
|
||||
rcs = append(rcs, newRollupConfig(rollupFirst, "open"))
|
||||
rcs = append(rcs, newRollupConfig(rollupLast, "close"))
|
||||
rcs = append(rcs, newRollupConfig(rollupMin, "low"))
|
||||
rcs = append(rcs, newRollupConfig(rollupMax, "high"))
|
||||
default:
|
||||
rcs = append(rcs, newRollupConfig(rf, ""))
|
||||
}
|
||||
return preFunc, rcs
|
||||
}
|
||||
|
||||
var bbPool bytesutil.ByteBufferPool
|
||||
|
||||
func evalNumber(ec *EvalConfig, n float64) []*timeseries {
|
||||
|
||||
@@ -4480,6 +4480,112 @@ func TestExecSuccess(t *testing.T) {
|
||||
resultExpected := []netstorage.Result{r}
|
||||
f(q, resultExpected)
|
||||
})
|
||||
t.Run(`hoeffding_bound_lower()`, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
q := `hoeffding_bound_lower(0.9, rand(0)[:10s])`
|
||||
r := netstorage.Result{
|
||||
MetricName: metricNameExpected,
|
||||
Values: []float64{0.2516770508510652, 0.2830570387745462, 0.27716232108436645, 0.3679356319931767, 0.3168460474120903, 0.23156726248243734},
|
||||
Timestamps: timestampsExpected,
|
||||
}
|
||||
resultExpected := []netstorage.Result{r}
|
||||
f(q, resultExpected)
|
||||
})
|
||||
t.Run(`hoeffding_bound_upper()`, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
q := `hoeffding_bound_upper(0.9, alias(rand(0), "foobar")[:10s])`
|
||||
r := netstorage.Result{
|
||||
MetricName: metricNameExpected,
|
||||
Values: []float64{0.6510581320042821, 0.7261021731890429, 0.7245290097397009, 0.8113950442584258, 0.7736122275568004, 0.6658564048254882},
|
||||
Timestamps: timestampsExpected,
|
||||
}
|
||||
r.MetricName.MetricGroup = []byte("foobar")
|
||||
resultExpected := []netstorage.Result{r}
|
||||
f(q, resultExpected)
|
||||
})
|
||||
t.Run(`aggr_over_time(single-func)`, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
q := `aggr_over_time("increase", rand(0)[:10s])`
|
||||
r1 := netstorage.Result{
|
||||
MetricName: metricNameExpected,
|
||||
Values: []float64{5.465672601448873, 6.642207999066246, 6.8400051805114295, 7.182425481980655, 5.1677922402706, 6.594060518641982},
|
||||
Timestamps: timestampsExpected,
|
||||
}
|
||||
r1.MetricName.Tags = []storage.Tag{{
|
||||
Key: []byte("rollup"),
|
||||
Value: []byte("increase"),
|
||||
}}
|
||||
resultExpected := []netstorage.Result{r1}
|
||||
f(q, resultExpected)
|
||||
})
|
||||
t.Run(`aggr_over_time(multi-func)`, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
q := `sort(aggr_over_time(("min_over_time", "count_over_time", "max_over_time"), round(rand(0),0.1)[:10s]))`
|
||||
r1 := netstorage.Result{
|
||||
MetricName: metricNameExpected,
|
||||
Values: []float64{0, 0, 0, 0, 0, 0},
|
||||
Timestamps: timestampsExpected,
|
||||
}
|
||||
r1.MetricName.Tags = []storage.Tag{{
|
||||
Key: []byte("rollup"),
|
||||
Value: []byte("min_over_time"),
|
||||
}}
|
||||
r2 := netstorage.Result{
|
||||
MetricName: metricNameExpected,
|
||||
Values: []float64{0.8, 0.9, 1, 0.9, 1, 0.9},
|
||||
Timestamps: timestampsExpected,
|
||||
}
|
||||
r2.MetricName.Tags = []storage.Tag{{
|
||||
Key: []byte("rollup"),
|
||||
Value: []byte("max_over_time"),
|
||||
}}
|
||||
r3 := netstorage.Result{
|
||||
MetricName: metricNameExpected,
|
||||
Values: []float64{20, 20, 20, 20, 20, 20},
|
||||
Timestamps: timestampsExpected,
|
||||
}
|
||||
r3.MetricName.Tags = []storage.Tag{{
|
||||
Key: []byte("rollup"),
|
||||
Value: []byte("count_over_time"),
|
||||
}}
|
||||
resultExpected := []netstorage.Result{r1, r2, r3}
|
||||
f(q, resultExpected)
|
||||
})
|
||||
t.Run(`avg(aggr_over_time(multi-func))`, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
q := `avg(aggr_over_time(("min_over_time", "max_over_time"), time()[:10s]))`
|
||||
r := netstorage.Result{
|
||||
MetricName: metricNameExpected,
|
||||
Values: []float64{905, 1105, 1305, 1505, 1705, 1905},
|
||||
Timestamps: timestampsExpected,
|
||||
}
|
||||
resultExpected := []netstorage.Result{r}
|
||||
f(q, resultExpected)
|
||||
})
|
||||
t.Run(`avg(aggr_over_time(multi-func)) by (rollup)`, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
q := `sort(avg(aggr_over_time(("min_over_time", "max_over_time"), time()[:10s])) by (rollup))`
|
||||
r1 := netstorage.Result{
|
||||
MetricName: metricNameExpected,
|
||||
Values: []float64{810, 1010, 1210, 1410, 1610, 1810},
|
||||
Timestamps: timestampsExpected,
|
||||
}
|
||||
r1.MetricName.Tags = []storage.Tag{{
|
||||
Key: []byte("rollup"),
|
||||
Value: []byte("min_over_time"),
|
||||
}}
|
||||
r2 := netstorage.Result{
|
||||
MetricName: metricNameExpected,
|
||||
Values: []float64{1000, 1200, 1400, 1600, 1800, 2000},
|
||||
Timestamps: timestampsExpected,
|
||||
}
|
||||
r2.MetricName.Tags = []storage.Tag{{
|
||||
Key: []byte("rollup"),
|
||||
Value: []byte("max_over_time"),
|
||||
}}
|
||||
resultExpected := []netstorage.Result{r1, r2}
|
||||
f(q, resultExpected)
|
||||
})
|
||||
t.Run(`rollup_candlestick()`, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
q := `sort(rollup_candlestick(round(rand(0),0.01)[:10s]))`
|
||||
@@ -4494,25 +4600,25 @@ func TestExecSuccess(t *testing.T) {
|
||||
}}
|
||||
r2 := netstorage.Result{
|
||||
MetricName: metricNameExpected,
|
||||
Values: []float64{0.32, 0.82, 0.13, 0.28, 0.86, 0.57},
|
||||
Values: []float64{0.85, 0.15, 0.43, 0.76, 0.47, 0.21},
|
||||
Timestamps: timestampsExpected,
|
||||
}
|
||||
r2.MetricName.Tags = []storage.Tag{{
|
||||
Key: []byte("rollup"),
|
||||
Value: []byte("close"),
|
||||
Value: []byte("open"),
|
||||
}}
|
||||
r3 := netstorage.Result{
|
||||
MetricName: metricNameExpected,
|
||||
Values: []float64{0.9, 0.32, 0.82, 0.13, 0.28, 0.86},
|
||||
Values: []float64{0.32, 0.82, 0.13, 0.28, 0.86, 0.57},
|
||||
Timestamps: timestampsExpected,
|
||||
}
|
||||
r3.MetricName.Tags = []storage.Tag{{
|
||||
Key: []byte("rollup"),
|
||||
Value: []byte("open"),
|
||||
Value: []byte("close"),
|
||||
}}
|
||||
r4 := netstorage.Result{
|
||||
MetricName: metricNameExpected,
|
||||
Values: []float64{0.9, 0.94, 0.97, 0.93, 0.98, 0.92},
|
||||
Values: []float64{0.85, 0.94, 0.97, 0.93, 0.98, 0.92},
|
||||
Timestamps: timestampsExpected,
|
||||
}
|
||||
r4.MetricName.Tags = []storage.Tag{{
|
||||
@@ -4560,7 +4666,7 @@ func TestExecSuccess(t *testing.T) {
|
||||
q := `sort(rollup(time()[:50s]))`
|
||||
r1 := netstorage.Result{
|
||||
MetricName: metricNameExpected,
|
||||
Values: []float64{800, 1000, 1200, 1400, 1600, 1800},
|
||||
Values: []float64{850, 1050, 1250, 1450, 1650, 1850},
|
||||
Timestamps: timestampsExpected,
|
||||
}
|
||||
r1.MetricName.Tags = []storage.Tag{{
|
||||
@@ -5181,6 +5287,18 @@ func TestExecError(t *testing.T) {
|
||||
f(`alias(1, "foo", "bar")`)
|
||||
f(`lifetime()`)
|
||||
f(`lag()`)
|
||||
f(`aggr_over_time()`)
|
||||
f(`aggr_over_time(foo)`)
|
||||
f(`aggr_over_time("foo", bar, 1)`)
|
||||
f(`sum(aggr_over_time())`)
|
||||
f(`sum(aggr_over_time(foo))`)
|
||||
f(`count(aggr_over_time("foo", bar, 1))`)
|
||||
f(`hoeffding_bound_lower()`)
|
||||
f(`hoeffding_bound_lower(1)`)
|
||||
f(`hoeffding_bound_lower(0.99, foo, 1)`)
|
||||
f(`hoeffding_bound_upper()`)
|
||||
f(`hoeffding_bound_upper(1)`)
|
||||
f(`hoeffding_bound_upper(0.99, foo, 1)`)
|
||||
|
||||
// Invalid argument type
|
||||
f(`median_over_time({}, 2)`)
|
||||
@@ -5216,6 +5334,8 @@ func TestExecError(t *testing.T) {
|
||||
f(`label_transform(1, "foo", "bar", 4)`)
|
||||
f(`label_transform(1, "foo", "invalid(regexp", "baz`)
|
||||
f(`alias(1, 2)`)
|
||||
f(`aggr_over_time(1, 2)`)
|
||||
f(`aggr_over_time(("foo", "bar"), 3)`)
|
||||
|
||||
// Duplicate timeseries
|
||||
f(`(label_set(1, "foo", "bar") or label_set(2, "foo", "baz"))
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
|
||||
"github.com/VictoriaMetrics/VictoriaMetrics/lib/decimal"
|
||||
"github.com/VictoriaMetrics/VictoriaMetrics/lib/logger"
|
||||
"github.com/VictoriaMetrics/VictoriaMetrics/lib/metricsql"
|
||||
"github.com/VictoriaMetrics/VictoriaMetrics/lib/storage"
|
||||
"github.com/VictoriaMetrics/metrics"
|
||||
"github.com/valyala/histogram"
|
||||
@@ -25,9 +26,9 @@ var rollupFuncs = map[string]newRollupFunc{
|
||||
"holt_winters": newRollupHoltWinters,
|
||||
"idelta": newRollupFuncOneArg(rollupIdelta),
|
||||
"increase": newRollupFuncOneArg(rollupIncrease), // + rollupFuncsRemoveCounterResets
|
||||
"irate": newRollupFuncOneArg(rollupIrate), // + rollupFuncsRemoveCounterResets
|
||||
"irate": newRollupFuncOneArg(rollupIderiv), // + rollupFuncsRemoveCounterResets
|
||||
"predict_linear": newRollupPredictLinear,
|
||||
"rate": newRollupFuncOneArg(rollupRate), // + rollupFuncsRemoveCounterResets
|
||||
"rate": newRollupFuncOneArg(rollupDerivFast), // + rollupFuncsRemoveCounterResets
|
||||
"resets": newRollupFuncOneArg(rollupResets),
|
||||
"avg_over_time": newRollupFuncOneArg(rollupAvg),
|
||||
"min_over_time": newRollupFuncOneArg(rollupMin),
|
||||
@@ -40,39 +41,92 @@ var rollupFuncs = map[string]newRollupFunc{
|
||||
"absent_over_time": newRollupFuncOneArg(rollupAbsent),
|
||||
|
||||
// Additional rollup funcs.
|
||||
"sum2_over_time": newRollupFuncOneArg(rollupSum2),
|
||||
"geomean_over_time": newRollupFuncOneArg(rollupGeomean),
|
||||
"first_over_time": newRollupFuncOneArg(rollupFirst),
|
||||
"last_over_time": newRollupFuncOneArg(rollupLast),
|
||||
"distinct_over_time": newRollupFuncOneArg(rollupDistinct),
|
||||
"increases_over_time": newRollupFuncOneArg(rollupIncreases),
|
||||
"decreases_over_time": newRollupFuncOneArg(rollupDecreases),
|
||||
"integrate": newRollupFuncOneArg(rollupIntegrate),
|
||||
"ideriv": newRollupFuncOneArg(rollupIderiv),
|
||||
"lifetime": newRollupFuncOneArg(rollupLifetime),
|
||||
"lag": newRollupFuncOneArg(rollupLag),
|
||||
"scrape_interval": newRollupFuncOneArg(rollupScrapeInterval),
|
||||
"share_le_over_time": newRollupShareLE,
|
||||
"share_gt_over_time": newRollupShareGT,
|
||||
"histogram_over_time": newRollupFuncOneArg(rollupHistogram),
|
||||
"rollup": newRollupFuncOneArg(rollupFake),
|
||||
"rollup_rate": newRollupFuncOneArg(rollupFake), // + rollupFuncsRemoveCounterResets
|
||||
"rollup_deriv": newRollupFuncOneArg(rollupFake),
|
||||
"rollup_delta": newRollupFuncOneArg(rollupFake),
|
||||
"rollup_increase": newRollupFuncOneArg(rollupFake), // + rollupFuncsRemoveCounterResets
|
||||
"rollup_candlestick": newRollupFuncOneArg(rollupFake),
|
||||
"sum2_over_time": newRollupFuncOneArg(rollupSum2),
|
||||
"geomean_over_time": newRollupFuncOneArg(rollupGeomean),
|
||||
"first_over_time": newRollupFuncOneArg(rollupFirst),
|
||||
"last_over_time": newRollupFuncOneArg(rollupLast),
|
||||
"distinct_over_time": newRollupFuncOneArg(rollupDistinct),
|
||||
"increases_over_time": newRollupFuncOneArg(rollupIncreases),
|
||||
"decreases_over_time": newRollupFuncOneArg(rollupDecreases),
|
||||
"integrate": newRollupFuncOneArg(rollupIntegrate),
|
||||
"ideriv": newRollupFuncOneArg(rollupIderiv),
|
||||
"lifetime": newRollupFuncOneArg(rollupLifetime),
|
||||
"lag": newRollupFuncOneArg(rollupLag),
|
||||
"scrape_interval": newRollupFuncOneArg(rollupScrapeInterval),
|
||||
"tmin_over_time": newRollupFuncOneArg(rollupTmin),
|
||||
"tmax_over_time": newRollupFuncOneArg(rollupTmax),
|
||||
"share_le_over_time": newRollupShareLE,
|
||||
"share_gt_over_time": newRollupShareGT,
|
||||
"histogram_over_time": newRollupFuncOneArg(rollupHistogram),
|
||||
"rollup": newRollupFuncOneArg(rollupFake),
|
||||
"rollup_rate": newRollupFuncOneArg(rollupFake), // + rollupFuncsRemoveCounterResets
|
||||
"rollup_deriv": newRollupFuncOneArg(rollupFake),
|
||||
"rollup_delta": newRollupFuncOneArg(rollupFake),
|
||||
"rollup_increase": newRollupFuncOneArg(rollupFake), // + rollupFuncsRemoveCounterResets
|
||||
"rollup_candlestick": newRollupFuncOneArg(rollupFake),
|
||||
"aggr_over_time": newRollupFuncTwoArgs(rollupFake),
|
||||
"hoeffding_bound_upper": newRollupHoeffdingBoundUpper,
|
||||
"hoeffding_bound_lower": newRollupHoeffdingBoundLower,
|
||||
}
|
||||
|
||||
var rollupFuncsMayAdjustWindow = map[string]bool{
|
||||
"default_rollup": true,
|
||||
"first_over_time": true,
|
||||
"last_over_time": true,
|
||||
"deriv": true,
|
||||
"deriv_fast": true,
|
||||
"irate": true,
|
||||
"rate": true,
|
||||
"lifetime": true,
|
||||
"scrape_interval": true,
|
||||
// rollupAggrFuncs are functions that can be passed to `aggr_over_time()`
|
||||
var rollupAggrFuncs = map[string]rollupFunc{
|
||||
// Standard rollup funcs from PromQL.
|
||||
"changes": rollupChanges,
|
||||
"delta": rollupDelta,
|
||||
"deriv": rollupDerivSlow,
|
||||
"deriv_fast": rollupDerivFast,
|
||||
"idelta": rollupIdelta,
|
||||
"increase": rollupIncrease, // + rollupFuncsRemoveCounterResets
|
||||
"irate": rollupIderiv, // + rollupFuncsRemoveCounterResets
|
||||
"rate": rollupDerivFast, // + rollupFuncsRemoveCounterResets
|
||||
"resets": rollupResets,
|
||||
"avg_over_time": rollupAvg,
|
||||
"min_over_time": rollupMin,
|
||||
"max_over_time": rollupMax,
|
||||
"sum_over_time": rollupSum,
|
||||
"count_over_time": rollupCount,
|
||||
"stddev_over_time": rollupStddev,
|
||||
"stdvar_over_time": rollupStdvar,
|
||||
"absent_over_time": rollupAbsent,
|
||||
|
||||
// Additional rollup funcs.
|
||||
"sum2_over_time": rollupSum2,
|
||||
"geomean_over_time": rollupGeomean,
|
||||
"first_over_time": rollupFirst,
|
||||
"last_over_time": rollupLast,
|
||||
"distinct_over_time": rollupDistinct,
|
||||
"increases_over_time": rollupIncreases,
|
||||
"decreases_over_time": rollupDecreases,
|
||||
"integrate": rollupIntegrate,
|
||||
"ideriv": rollupIderiv,
|
||||
"lifetime": rollupLifetime,
|
||||
"lag": rollupLag,
|
||||
"scrape_interval": rollupScrapeInterval,
|
||||
"tmin_over_time": rollupTmin,
|
||||
"tmax_over_time": rollupTmax,
|
||||
}
|
||||
|
||||
var rollupFuncsCannotAdjustWindow = map[string]bool{
|
||||
"changes": true,
|
||||
"delta": true,
|
||||
"holt_winters": true,
|
||||
"idelta": true,
|
||||
"increase": true,
|
||||
"predict_linear": true,
|
||||
"resets": true,
|
||||
"sum_over_time": true,
|
||||
"count_over_time": true,
|
||||
"quantile_over_time": true,
|
||||
"stddev_over_time": true,
|
||||
"stdvar_over_time": true,
|
||||
"absent_over_time": true,
|
||||
"sum2_over_time": true,
|
||||
"geomean_over_time": true,
|
||||
"distinct_over_time": true,
|
||||
"increases_over_time": true,
|
||||
"decreases_over_time": true,
|
||||
"integrate": true,
|
||||
}
|
||||
|
||||
var rollupFuncsRemoveCounterResets = map[string]bool{
|
||||
@@ -84,13 +138,64 @@ var rollupFuncsRemoveCounterResets = map[string]bool{
|
||||
}
|
||||
|
||||
var rollupFuncsKeepMetricGroup = map[string]bool{
|
||||
"default_rollup": true,
|
||||
"avg_over_time": true,
|
||||
"min_over_time": true,
|
||||
"max_over_time": true,
|
||||
"quantile_over_time": true,
|
||||
"rollup": true,
|
||||
"geomean_over_time": true,
|
||||
"default_rollup": true,
|
||||
"avg_over_time": true,
|
||||
"min_over_time": true,
|
||||
"max_over_time": true,
|
||||
"quantile_over_time": true,
|
||||
"rollup": true,
|
||||
"geomean_over_time": true,
|
||||
"hoeffding_bound_lower": true,
|
||||
"hoeffding_bound_upper": true,
|
||||
}
|
||||
|
||||
func getRollupAggrFuncNames(expr metricsql.Expr) ([]string, error) {
|
||||
afe, ok := expr.(*metricsql.AggrFuncExpr)
|
||||
if ok {
|
||||
// This is for incremental aggregate function case:
|
||||
//
|
||||
// sum(aggr_over_time(...))
|
||||
//
|
||||
// See aggr_incremental.go for details.
|
||||
expr = afe.Args[0]
|
||||
}
|
||||
fe, ok := expr.(*metricsql.FuncExpr)
|
||||
if !ok {
|
||||
logger.Panicf("BUG: unexpected expression; want metricsql.FuncExpr; got %T; value: %s", expr, expr.AppendString(nil))
|
||||
}
|
||||
if fe.Name != "aggr_over_time" {
|
||||
logger.Panicf("BUG: unexpected function name: %q; want `aggr_over_time`", fe.Name)
|
||||
}
|
||||
if len(fe.Args) != 2 {
|
||||
return nil, fmt.Errorf("unexpected number of args to aggr_over_time(); got %d; want %d", len(fe.Args), 2)
|
||||
}
|
||||
arg := fe.Args[0]
|
||||
var aggrFuncNames []string
|
||||
if se, ok := arg.(*metricsql.StringExpr); ok {
|
||||
aggrFuncNames = append(aggrFuncNames, se.S)
|
||||
} else {
|
||||
fe, ok := arg.(*metricsql.FuncExpr)
|
||||
if !ok || fe.Name != "" {
|
||||
return nil, fmt.Errorf("%s cannot be passed to aggr_over_time(); expecting quoted aggregate function name or a list of quoted aggregate function names",
|
||||
arg.AppendString(nil))
|
||||
}
|
||||
for _, e := range fe.Args {
|
||||
se, ok := e.(*metricsql.StringExpr)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("%s cannot be passed here; expecting quoted aggregate function name", e.AppendString(nil))
|
||||
}
|
||||
aggrFuncNames = append(aggrFuncNames, se.S)
|
||||
}
|
||||
}
|
||||
if len(aggrFuncNames) == 0 {
|
||||
return nil, fmt.Errorf("aggr_over_time() must contain at least a single aggregate function name")
|
||||
}
|
||||
for _, s := range aggrFuncNames {
|
||||
if rollupAggrFuncs[s] == nil {
|
||||
return nil, fmt.Errorf("%q cannot be used in `aggr_over_time` function; expecting quoted aggregate function name", s)
|
||||
}
|
||||
}
|
||||
return aggrFuncNames, nil
|
||||
}
|
||||
|
||||
func getRollupArgIdx(funcName string) int {
|
||||
@@ -98,10 +203,84 @@ func getRollupArgIdx(funcName string) int {
|
||||
if rollupFuncs[funcName] == nil {
|
||||
logger.Panicf("BUG: getRollupArgIdx is called for non-rollup func %q", funcName)
|
||||
}
|
||||
if funcName == "quantile_over_time" {
|
||||
switch funcName {
|
||||
case "quantile_over_time", "aggr_over_time",
|
||||
"hoeffding_bound_lower", "hoeffding_bound_upper":
|
||||
return 1
|
||||
default:
|
||||
return 0
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func getRollupConfigs(name string, rf rollupFunc, expr metricsql.Expr, start, end, step, window int64, lookbackDelta int64, sharedTimestamps []int64) (
|
||||
func(values []float64, timestamps []int64), []*rollupConfig, error) {
|
||||
preFunc := func(values []float64, timestamps []int64) {}
|
||||
if rollupFuncsRemoveCounterResets[name] {
|
||||
preFunc = func(values []float64, timestamps []int64) {
|
||||
removeCounterResets(values)
|
||||
}
|
||||
}
|
||||
newRollupConfig := func(rf rollupFunc, tagValue string) *rollupConfig {
|
||||
return &rollupConfig{
|
||||
TagValue: tagValue,
|
||||
Func: rf,
|
||||
Start: start,
|
||||
End: end,
|
||||
Step: step,
|
||||
Window: window,
|
||||
MayAdjustWindow: !rollupFuncsCannotAdjustWindow[name],
|
||||
LookbackDelta: lookbackDelta,
|
||||
Timestamps: sharedTimestamps,
|
||||
}
|
||||
}
|
||||
appendRollupConfigs := func(dst []*rollupConfig) []*rollupConfig {
|
||||
dst = append(dst, newRollupConfig(rollupMin, "min"))
|
||||
dst = append(dst, newRollupConfig(rollupMax, "max"))
|
||||
dst = append(dst, newRollupConfig(rollupAvg, "avg"))
|
||||
return dst
|
||||
}
|
||||
var rcs []*rollupConfig
|
||||
switch name {
|
||||
case "rollup":
|
||||
rcs = appendRollupConfigs(rcs)
|
||||
case "rollup_rate", "rollup_deriv":
|
||||
preFuncPrev := preFunc
|
||||
preFunc = func(values []float64, timestamps []int64) {
|
||||
preFuncPrev(values, timestamps)
|
||||
derivValues(values, timestamps)
|
||||
}
|
||||
rcs = appendRollupConfigs(rcs)
|
||||
case "rollup_increase", "rollup_delta":
|
||||
preFuncPrev := preFunc
|
||||
preFunc = func(values []float64, timestamps []int64) {
|
||||
preFuncPrev(values, timestamps)
|
||||
deltaValues(values)
|
||||
}
|
||||
rcs = appendRollupConfigs(rcs)
|
||||
case "rollup_candlestick":
|
||||
rcs = append(rcs, newRollupConfig(rollupFirst, "open"))
|
||||
rcs = append(rcs, newRollupConfig(rollupLast, "close"))
|
||||
rcs = append(rcs, newRollupConfig(rollupMin, "low"))
|
||||
rcs = append(rcs, newRollupConfig(rollupMax, "high"))
|
||||
case "aggr_over_time":
|
||||
aggrFuncNames, err := getRollupAggrFuncNames(expr)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("invalid args to %s: %s", expr.AppendString(nil), err)
|
||||
}
|
||||
for _, aggrFuncName := range aggrFuncNames {
|
||||
if rollupFuncsRemoveCounterResets[aggrFuncName] {
|
||||
// There is no need to save the previous preFunc, since it is either empty or the same.
|
||||
preFunc = func(values []float64, timestamps []int64) {
|
||||
removeCounterResets(values)
|
||||
}
|
||||
}
|
||||
rf := rollupAggrFuncs[aggrFuncName]
|
||||
rcs = append(rcs, newRollupConfig(rf, aggrFuncName))
|
||||
}
|
||||
default:
|
||||
rcs = append(rcs, newRollupConfig(rf, ""))
|
||||
}
|
||||
return preFunc, rcs, nil
|
||||
}
|
||||
|
||||
func getRollupFunc(funcName string) newRollupFunc {
|
||||
@@ -115,10 +294,9 @@ type rollupFuncArg struct {
|
||||
values []float64
|
||||
timestamps []int64
|
||||
|
||||
currTimestamp int64
|
||||
idx int
|
||||
step int64
|
||||
scrapeInterval int64
|
||||
currTimestamp int64
|
||||
idx int
|
||||
step int64
|
||||
|
||||
// Real previous value even if it is located too far from the current window.
|
||||
// It matches prevValue if prevValue is not nan.
|
||||
@@ -135,7 +313,6 @@ func (rfa *rollupFuncArg) reset() {
|
||||
rfa.currTimestamp = 0
|
||||
rfa.idx = 0
|
||||
rfa.step = 0
|
||||
rfa.scrapeInterval = 0
|
||||
rfa.realPrevValue = nan
|
||||
rfa.tsm = nil
|
||||
}
|
||||
@@ -276,7 +453,6 @@ func (rc *rollupConfig) doInternal(dstValues []float64, tsm *timeseriesMap, valu
|
||||
rfa := getRollupFuncArg()
|
||||
rfa.idx = 0
|
||||
rfa.step = rc.Step
|
||||
rfa.scrapeInterval = scrapeInterval
|
||||
rfa.realPrevValue = nan
|
||||
rfa.tsm = tsm
|
||||
|
||||
@@ -490,6 +666,15 @@ func newRollupFuncOneArg(rf rollupFunc) newRollupFunc {
|
||||
}
|
||||
}
|
||||
|
||||
func newRollupFuncTwoArgs(rf rollupFunc) newRollupFunc {
|
||||
return func(args []interface{}) (rollupFunc, error) {
|
||||
if err := expectRollupArgsNum(args, 2); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return rf, nil
|
||||
}
|
||||
}
|
||||
|
||||
func newRollupHoltWinters(args []interface{}) (rollupFunc, error) {
|
||||
if err := expectRollupArgsNum(args, 3); err != nil {
|
||||
return nil, err
|
||||
@@ -648,6 +833,66 @@ func newRollupShareFilter(args []interface{}, countFilter func(values []float64,
|
||||
return rf, nil
|
||||
}
|
||||
|
||||
func newRollupHoeffdingBoundLower(args []interface{}) (rollupFunc, error) {
|
||||
if err := expectRollupArgsNum(args, 2); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
phis, err := getScalar(args[0], 0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rf := func(rfa *rollupFuncArg) float64 {
|
||||
bound, avg := rollupHoeffdingBoundInternal(rfa, phis)
|
||||
return avg - bound
|
||||
}
|
||||
return rf, nil
|
||||
}
|
||||
|
||||
func newRollupHoeffdingBoundUpper(args []interface{}) (rollupFunc, error) {
|
||||
if err := expectRollupArgsNum(args, 2); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
phis, err := getScalar(args[0], 0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rf := func(rfa *rollupFuncArg) float64 {
|
||||
bound, avg := rollupHoeffdingBoundInternal(rfa, phis)
|
||||
return avg + bound
|
||||
}
|
||||
return rf, nil
|
||||
}
|
||||
|
||||
func rollupHoeffdingBoundInternal(rfa *rollupFuncArg, phis []float64) (float64, float64) {
|
||||
// There is no need in handling NaNs here, since they must be cleaned up
|
||||
// before calling rollup funcs.
|
||||
values := rfa.values
|
||||
if len(values) == 0 {
|
||||
return nan, nan
|
||||
}
|
||||
if len(values) == 1 {
|
||||
return 0, values[0]
|
||||
}
|
||||
vMax := rollupMax(rfa)
|
||||
vMin := rollupMin(rfa)
|
||||
vAvg := rollupAvg(rfa)
|
||||
vRange := vMax - vMin
|
||||
if vRange <= 0 {
|
||||
return 0, vAvg
|
||||
}
|
||||
phi := phis[rfa.idx]
|
||||
if phi >= 1 {
|
||||
return inf, vAvg
|
||||
}
|
||||
if phi <= 0 {
|
||||
return 0, vAvg
|
||||
}
|
||||
// See https://en.wikipedia.org/wiki/Hoeffding%27s_inequality
|
||||
// and https://www.youtube.com/watch?v=6UwcqiNsZ8U&feature=youtu.be&t=1237
|
||||
bound := vRange * math.Sqrt(math.Log(1/(1-phi))/(2*float64(len(values))))
|
||||
return bound, vAvg
|
||||
}
|
||||
|
||||
func newRollupQuantile(args []interface{}) (rollupFunc, error) {
|
||||
if err := expectRollupArgsNum(args, 2); err != nil {
|
||||
return nil, err
|
||||
@@ -702,7 +947,10 @@ func rollupAvg(rfa *rollupFuncArg) float64 {
|
||||
// before calling rollup funcs.
|
||||
values := rfa.values
|
||||
if len(values) == 0 {
|
||||
return rfa.prevValue
|
||||
// Do not take into account rfa.prevValue, since it may lead
|
||||
// to inconsistent results comparing to Prometheus on broken time series
|
||||
// with irregular data points.
|
||||
return nan
|
||||
}
|
||||
var sum float64
|
||||
for _, v := range values {
|
||||
@@ -714,14 +962,14 @@ func rollupAvg(rfa *rollupFuncArg) float64 {
|
||||
func rollupMin(rfa *rollupFuncArg) float64 {
|
||||
// There is no need in handling NaNs here, since they must be cleaned up
|
||||
// before calling rollup funcs.
|
||||
minValue := rfa.prevValue
|
||||
values := rfa.values
|
||||
if math.IsNaN(minValue) {
|
||||
if len(values) == 0 {
|
||||
return nan
|
||||
}
|
||||
minValue = values[0]
|
||||
if len(values) == 0 {
|
||||
// Do not take into account rfa.prevValue, since it may lead
|
||||
// to inconsistent results comparing to Prometheus on broken time series
|
||||
// with irregular data points.
|
||||
return nan
|
||||
}
|
||||
minValue := values[0]
|
||||
for _, v := range values {
|
||||
if v < minValue {
|
||||
minValue = v
|
||||
@@ -733,14 +981,14 @@ func rollupMin(rfa *rollupFuncArg) float64 {
|
||||
func rollupMax(rfa *rollupFuncArg) float64 {
|
||||
// There is no need in handling NaNs here, since they must be cleaned up
|
||||
// before calling rollup funcs.
|
||||
maxValue := rfa.prevValue
|
||||
values := rfa.values
|
||||
if math.IsNaN(maxValue) {
|
||||
if len(values) == 0 {
|
||||
return nan
|
||||
}
|
||||
maxValue = values[0]
|
||||
if len(values) == 0 {
|
||||
// Do not take into account rfa.prevValue, since it may lead
|
||||
// to inconsistent results comparing to Prometheus on broken time series
|
||||
// with irregular data points.
|
||||
return nan
|
||||
}
|
||||
maxValue := values[0]
|
||||
for _, v := range values {
|
||||
if v > maxValue {
|
||||
maxValue = v
|
||||
@@ -749,6 +997,44 @@ func rollupMax(rfa *rollupFuncArg) float64 {
|
||||
return maxValue
|
||||
}
|
||||
|
||||
func rollupTmin(rfa *rollupFuncArg) float64 {
|
||||
// There is no need in handling NaNs here, since they must be cleaned up
|
||||
// before calling rollup funcs.
|
||||
values := rfa.values
|
||||
timestamps := rfa.timestamps
|
||||
if len(values) == 0 {
|
||||
return nan
|
||||
}
|
||||
minValue := values[0]
|
||||
minTimestamp := timestamps[0]
|
||||
for i, v := range values {
|
||||
if v < minValue {
|
||||
minValue = v
|
||||
minTimestamp = timestamps[i]
|
||||
}
|
||||
}
|
||||
return float64(minTimestamp) * 1e-3
|
||||
}
|
||||
|
||||
func rollupTmax(rfa *rollupFuncArg) float64 {
|
||||
// There is no need in handling NaNs here, since they must be cleaned up
|
||||
// before calling rollup funcs.
|
||||
values := rfa.values
|
||||
timestamps := rfa.timestamps
|
||||
if len(values) == 0 {
|
||||
return nan
|
||||
}
|
||||
maxValue := values[0]
|
||||
maxTimestamp := timestamps[0]
|
||||
for i, v := range values {
|
||||
if v > maxValue {
|
||||
maxValue = v
|
||||
maxTimestamp = timestamps[i]
|
||||
}
|
||||
}
|
||||
return float64(maxTimestamp) * 1e-3
|
||||
}
|
||||
|
||||
func rollupSum(rfa *rollupFuncArg) float64 {
|
||||
// There is no need in handling NaNs here, since they must be cleaned up
|
||||
// before calling rollup funcs.
|
||||
@@ -865,7 +1151,10 @@ func rollupDeltaInternal(rfa *rollupFuncArg, canUseRealPrevValue bool) float64 {
|
||||
return nan
|
||||
}
|
||||
// Assume that the previous non-existing value was 0.
|
||||
prevValue = getPrevValue(rfa, canUseRealPrevValue)
|
||||
prevValue = 0
|
||||
if canUseRealPrevValue && !math.IsNaN(rfa.prevValue) {
|
||||
prevValue = rfa.prevValue
|
||||
}
|
||||
}
|
||||
if len(values) == 0 {
|
||||
// Assume that the value didn't change on the given interval.
|
||||
@@ -906,14 +1195,6 @@ func rollupDerivSlow(rfa *rollupFuncArg) float64 {
|
||||
}
|
||||
|
||||
func rollupDerivFast(rfa *rollupFuncArg) float64 {
|
||||
return rollupDerivFastInternal(rfa, false)
|
||||
}
|
||||
|
||||
func rollupRate(rfa *rollupFuncArg) float64 {
|
||||
return rollupDerivFastInternal(rfa, true)
|
||||
}
|
||||
|
||||
func rollupDerivFastInternal(rfa *rollupFuncArg, canUseRealPrevValue bool) float64 {
|
||||
// There is no need in handling NaNs here, since they must be cleaned up
|
||||
// before calling rollup funcs.
|
||||
values := rfa.values
|
||||
@@ -924,9 +1205,21 @@ func rollupDerivFastInternal(rfa *rollupFuncArg, canUseRealPrevValue bool) float
|
||||
if len(values) == 0 {
|
||||
return nan
|
||||
}
|
||||
// Assume that the value changed from 0 to the current value during rfa.scrapeInterval
|
||||
prevValue = getPrevValue(rfa, canUseRealPrevValue)
|
||||
prevTimestamp = timestamps[0] - rfa.scrapeInterval
|
||||
if len(values) == 1 {
|
||||
// It is impossible to determine the duration during which the value changed
|
||||
// from 0 to the current value.
|
||||
// The following attempts didn't work well:
|
||||
// - using scrape interval as the duration. It fails on Prometheus restarts when it
|
||||
// skips scraping for the counter. This results in too high rate() value for the first point
|
||||
// after Prometheus restarts.
|
||||
// - using window or step as the duration. It results in too small rate() values for the first
|
||||
// points of time series.
|
||||
//
|
||||
// So just return nan
|
||||
return nan
|
||||
}
|
||||
prevValue = values[0]
|
||||
prevTimestamp = timestamps[0]
|
||||
} else if len(values) == 0 {
|
||||
// Assume that the value didn't change on the given interval.
|
||||
return 0
|
||||
@@ -939,14 +1232,6 @@ func rollupDerivFastInternal(rfa *rollupFuncArg, canUseRealPrevValue bool) float
|
||||
}
|
||||
|
||||
func rollupIderiv(rfa *rollupFuncArg) float64 {
|
||||
return rollupIderivInternal(rfa, false)
|
||||
}
|
||||
|
||||
func rollupIrate(rfa *rollupFuncArg) float64 {
|
||||
return rollupIderivInternal(rfa, true)
|
||||
}
|
||||
|
||||
func rollupIderivInternal(rfa *rollupFuncArg, canUseRealPrevValue bool) float64 {
|
||||
// There is no need in handling NaNs here, since they must be cleaned up
|
||||
// before calling rollup funcs.
|
||||
values := rfa.values
|
||||
@@ -955,14 +1240,20 @@ func rollupIderivInternal(rfa *rollupFuncArg, canUseRealPrevValue bool) float64
|
||||
if len(values) == 0 {
|
||||
return nan
|
||||
}
|
||||
prevValue := rfa.prevValue
|
||||
prevTimestamp := rfa.prevTimestamp
|
||||
if math.IsNaN(prevValue) {
|
||||
// Assume that the value changed from 0 to the current value during rfa.scrapeInterval.
|
||||
prevValue = getPrevValue(rfa, canUseRealPrevValue)
|
||||
prevTimestamp = timestamps[0] - rfa.scrapeInterval
|
||||
if math.IsNaN(rfa.prevValue) {
|
||||
// It is impossible to determine the duration during which the value changed
|
||||
// from 0 to the current value.
|
||||
// The following attempts didn't work well:
|
||||
// - using scrape interval as the duration. It fails on Prometheus restarts when it
|
||||
// skips scraping for the counter. This results in too high rate() value for the first point
|
||||
// after Prometheus restarts.
|
||||
// - using window or step as the duration. It results in too small rate() values for the first
|
||||
// points of time series.
|
||||
//
|
||||
// So just return nan
|
||||
return nan
|
||||
}
|
||||
return (values[0] - prevValue) / (float64(timestamps[0]-prevTimestamp) * 1e-3)
|
||||
return (values[0] - rfa.prevValue) / (float64(timestamps[0]-rfa.prevTimestamp) * 1e-3)
|
||||
}
|
||||
vEnd := values[len(values)-1]
|
||||
tEnd := timestamps[len(timestamps)-1]
|
||||
@@ -989,14 +1280,6 @@ func rollupIderivInternal(rfa *rollupFuncArg, canUseRealPrevValue bool) float64
|
||||
return dv / (float64(dt) * 1e-3)
|
||||
}
|
||||
|
||||
func getPrevValue(rfa *rollupFuncArg, canUseRealPrevValue bool) float64 {
|
||||
prevValue := rfa.realPrevValue
|
||||
if !canUseRealPrevValue || math.IsNaN(prevValue) {
|
||||
return 0
|
||||
}
|
||||
return prevValue
|
||||
}
|
||||
|
||||
func rollupLifetime(rfa *rollupFuncArg) float64 {
|
||||
// Calculate the duration between the first and the last data points.
|
||||
timestamps := rfa.timestamps
|
||||
@@ -1122,16 +1405,13 @@ func rollupResets(rfa *rollupFuncArg) float64 {
|
||||
}
|
||||
|
||||
func rollupFirst(rfa *rollupFuncArg) float64 {
|
||||
// See https://prometheus.io/docs/prometheus/latest/querying/basics/#staleness
|
||||
v := rfa.prevValue
|
||||
if !math.IsNaN(v) {
|
||||
return v
|
||||
}
|
||||
|
||||
// There is no need in handling NaNs here, since they must be cleaned up
|
||||
// before calling rollup funcs.
|
||||
values := rfa.values
|
||||
if len(values) == 0 {
|
||||
// Do not take into account rfa.prevValue, since it may lead
|
||||
// to inconsistent results comparing to Prometheus on broken time series
|
||||
// with irregular data points.
|
||||
return nan
|
||||
}
|
||||
return values[0]
|
||||
@@ -1144,7 +1424,10 @@ func rollupLast(rfa *rollupFuncArg) float64 {
|
||||
// before calling rollup funcs.
|
||||
values := rfa.values
|
||||
if len(values) == 0 {
|
||||
return rfa.prevValue
|
||||
// Do not take into account rfa.prevValue, since it may lead
|
||||
// to inconsistent results comparing to Prometheus on broken time series
|
||||
// with irregular data points.
|
||||
return nan
|
||||
}
|
||||
return values[len(values)-1]
|
||||
}
|
||||
|
||||
@@ -42,14 +42,13 @@ func TestRollupIderivDuplicateTimestamps(t *testing.T) {
|
||||
}
|
||||
|
||||
rfa = &rollupFuncArg{
|
||||
prevValue: nan,
|
||||
values: []float64{15},
|
||||
timestamps: []int64{100},
|
||||
scrapeInterval: 200,
|
||||
prevValue: nan,
|
||||
values: []float64{15},
|
||||
timestamps: []int64{100},
|
||||
}
|
||||
n = rollupIderiv(rfa)
|
||||
if n != 75 {
|
||||
t.Fatalf("unexpected value; got %v; want %v", n, 75)
|
||||
if !math.IsNaN(n) {
|
||||
t.Fatalf("unexpected value; got %v; want %v", n, nan)
|
||||
}
|
||||
|
||||
rfa = &rollupFuncArg{
|
||||
@@ -311,6 +310,48 @@ func TestRollupHoltWinters(t *testing.T) {
|
||||
f(0.9, 0.9, 33.99637566941818)
|
||||
}
|
||||
|
||||
func TestRollupHoeffdingBoundLower(t *testing.T) {
|
||||
f := func(phi, vExpected float64) {
|
||||
t.Helper()
|
||||
phis := []*timeseries{{
|
||||
Values: []float64{phi},
|
||||
Timestamps: []int64{123},
|
||||
}}
|
||||
var me metricsql.MetricExpr
|
||||
args := []interface{}{phis, &metricsql.RollupExpr{Expr: &me}}
|
||||
testRollupFunc(t, "hoeffding_bound_lower", args, &me, vExpected)
|
||||
}
|
||||
|
||||
f(0.5, 28.21949401521037)
|
||||
f(-1, 47.083333333333336)
|
||||
f(0, 47.083333333333336)
|
||||
f(1, -inf)
|
||||
f(2, -inf)
|
||||
f(0.1, 39.72878000047643)
|
||||
f(0.9, 12.701803086472331)
|
||||
}
|
||||
|
||||
func TestRollupHoeffdingBoundUpper(t *testing.T) {
|
||||
f := func(phi, vExpected float64) {
|
||||
t.Helper()
|
||||
phis := []*timeseries{{
|
||||
Values: []float64{phi},
|
||||
Timestamps: []int64{123},
|
||||
}}
|
||||
var me metricsql.MetricExpr
|
||||
args := []interface{}{phis, &metricsql.RollupExpr{Expr: &me}}
|
||||
testRollupFunc(t, "hoeffding_bound_upper", args, &me, vExpected)
|
||||
}
|
||||
|
||||
f(0.5, 65.9471726514563)
|
||||
f(-1, 47.083333333333336)
|
||||
f(0, 47.083333333333336)
|
||||
f(1, inf)
|
||||
f(2, inf)
|
||||
f(0.1, 54.43788666619024)
|
||||
f(0.9, 81.46486358019433)
|
||||
}
|
||||
|
||||
func TestRollupNewRollupFuncSuccess(t *testing.T) {
|
||||
f := func(funcName string, vExpected float64) {
|
||||
t.Helper()
|
||||
@@ -323,15 +364,17 @@ func TestRollupNewRollupFuncSuccess(t *testing.T) {
|
||||
f("changes", 11)
|
||||
f("delta", 34)
|
||||
f("deriv", -266.85860231406065)
|
||||
f("deriv_fast", 272)
|
||||
f("deriv_fast", -712)
|
||||
f("idelta", 0)
|
||||
f("increase", 398)
|
||||
f("irate", 0)
|
||||
f("rate", 3184)
|
||||
f("rate", 2200)
|
||||
f("resets", 5)
|
||||
f("avg_over_time", 47.083333333333336)
|
||||
f("min_over_time", 12)
|
||||
f("max_over_time", 123)
|
||||
f("tmin_over_time", 0.08)
|
||||
f("tmax_over_time", 0.005)
|
||||
f("sum_over_time", 565)
|
||||
f("sum2_over_time", 37951)
|
||||
f("geomean_over_time", 39.33466603189148)
|
||||
@@ -458,7 +501,7 @@ func TestRollupNoWindowPartialPoints(t *testing.T) {
|
||||
}
|
||||
rc.Timestamps = getTimestamps(rc.Start, rc.End, rc.Step)
|
||||
values := rc.Do(nil, testValues, testTimestamps)
|
||||
valuesExpected := []float64{nan, 123, 123, 123, 34, 34}
|
||||
valuesExpected := []float64{nan, 123, nan, 34, nan, 44}
|
||||
timestampsExpected := []int64{0, 5, 10, 15, 20, 25}
|
||||
testRowsEqual(t, values, rc.Timestamps, valuesExpected, timestampsExpected)
|
||||
})
|
||||
@@ -472,7 +515,7 @@ func TestRollupNoWindowPartialPoints(t *testing.T) {
|
||||
}
|
||||
rc.Timestamps = getTimestamps(rc.Start, rc.End, rc.Step)
|
||||
values := rc.Do(nil, testValues, testTimestamps)
|
||||
valuesExpected := []float64{12, 44, 34, nan}
|
||||
valuesExpected := []float64{44, 32, 34, nan}
|
||||
timestampsExpected := []int64{100, 120, 140, 160}
|
||||
testRowsEqual(t, values, rc.Timestamps, valuesExpected, timestampsExpected)
|
||||
})
|
||||
@@ -486,7 +529,7 @@ func TestRollupNoWindowPartialPoints(t *testing.T) {
|
||||
}
|
||||
rc.Timestamps = getTimestamps(rc.Start, rc.End, rc.Step)
|
||||
values := rc.Do(nil, testValues, testTimestamps)
|
||||
valuesExpected := []float64{nan, nan, 123, 54, 44}
|
||||
valuesExpected := []float64{nan, nan, 123, 34, 32}
|
||||
timestampsExpected := []int64{-50, 0, 50, 100, 150}
|
||||
testRowsEqual(t, values, rc.Timestamps, valuesExpected, timestampsExpected)
|
||||
})
|
||||
@@ -548,7 +591,7 @@ func TestRollupFuncsLookbackDelta(t *testing.T) {
|
||||
}
|
||||
rc.Timestamps = getTimestamps(rc.Start, rc.End, rc.Step)
|
||||
values := rc.Do(nil, testValues, testTimestamps)
|
||||
valuesExpected := []float64{99, 12, 44, nan, 32, 34, nan}
|
||||
valuesExpected := []float64{99, nan, 44, nan, 32, 34, nan}
|
||||
timestampsExpected := []int64{80, 90, 100, 110, 120, 130, 140}
|
||||
testRowsEqual(t, values, rc.Timestamps, valuesExpected, timestampsExpected)
|
||||
})
|
||||
@@ -562,7 +605,7 @@ func TestRollupFuncsLookbackDelta(t *testing.T) {
|
||||
}
|
||||
rc.Timestamps = getTimestamps(rc.Start, rc.End, rc.Step)
|
||||
values := rc.Do(nil, testValues, testTimestamps)
|
||||
valuesExpected := []float64{99, 12, 44, 44, 32, 34, nan}
|
||||
valuesExpected := []float64{99, nan, 44, nan, 32, 34, nan}
|
||||
timestampsExpected := []int64{80, 90, 100, 110, 120, 130, 140}
|
||||
testRowsEqual(t, values, rc.Timestamps, valuesExpected, timestampsExpected)
|
||||
})
|
||||
@@ -576,7 +619,7 @@ func TestRollupFuncsLookbackDelta(t *testing.T) {
|
||||
}
|
||||
rc.Timestamps = getTimestamps(rc.Start, rc.End, rc.Step)
|
||||
values := rc.Do(nil, testValues, testTimestamps)
|
||||
valuesExpected := []float64{34, 12, 12, 44, 44, 34, nan}
|
||||
valuesExpected := []float64{99, nan, 44, nan, 32, 34, nan}
|
||||
timestampsExpected := []int64{80, 90, 100, 110, 120, 130, 140}
|
||||
testRowsEqual(t, values, rc.Timestamps, valuesExpected, timestampsExpected)
|
||||
})
|
||||
@@ -593,7 +636,7 @@ func TestRollupFuncsNoWindow(t *testing.T) {
|
||||
}
|
||||
rc.Timestamps = getTimestamps(rc.Start, rc.End, rc.Step)
|
||||
values := rc.Do(nil, testValues, testTimestamps)
|
||||
valuesExpected := []float64{nan, 123, 21, 12, 34}
|
||||
valuesExpected := []float64{nan, 123, 54, 44, 34}
|
||||
timestampsExpected := []int64{0, 40, 80, 120, 160}
|
||||
testRowsEqual(t, values, rc.Timestamps, valuesExpected, timestampsExpected)
|
||||
})
|
||||
@@ -621,7 +664,7 @@ func TestRollupFuncsNoWindow(t *testing.T) {
|
||||
}
|
||||
rc.Timestamps = getTimestamps(rc.Start, rc.End, rc.Step)
|
||||
values := rc.Do(nil, testValues, testTimestamps)
|
||||
valuesExpected := []float64{nan, 21, 12, 12, 34}
|
||||
valuesExpected := []float64{nan, 21, 12, 32, 34}
|
||||
timestampsExpected := []int64{0, 40, 80, 120, 160}
|
||||
testRowsEqual(t, values, rc.Timestamps, valuesExpected, timestampsExpected)
|
||||
})
|
||||
@@ -831,7 +874,7 @@ func TestRollupFuncsNoWindow(t *testing.T) {
|
||||
}
|
||||
rc.Timestamps = getTimestamps(rc.Start, rc.End, rc.Step)
|
||||
values := rc.Do(nil, testValues, testTimestamps)
|
||||
valuesExpected := []float64{nan, nan, 10250, 0, -8900, 0}
|
||||
valuesExpected := []float64{nan, nan, nan, 0, -8900, 0}
|
||||
timestampsExpected := []int64{0, 4, 8, 12, 16, 20}
|
||||
testRowsEqual(t, values, rc.Timestamps, valuesExpected, timestampsExpected)
|
||||
})
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# All these commands must run from repository root.
|
||||
|
||||
DOCKER_NAMESPACE := docker.io/victoriametrics
|
||||
BUILDER_IMAGE := local/builder:go1.13.5
|
||||
BUILDER_IMAGE := local/builder:go1.13.6
|
||||
CERTS_IMAGE := local/certs:1.0.3
|
||||
|
||||
package-certs:
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
FROM golang:1.13.5
|
||||
FROM golang:1.13.6
|
||||
STOPSIGNAL SIGINT
|
||||
|
||||
@@ -2,7 +2,7 @@ version: '3.5'
|
||||
services:
|
||||
prometheus:
|
||||
container_name: prometheus
|
||||
image: prom/prometheus:v2.14.0
|
||||
image: prom/prometheus:v2.15.2
|
||||
depends_on:
|
||||
- "victoriametrics"
|
||||
ports:
|
||||
@@ -35,7 +35,7 @@ services:
|
||||
restart: always
|
||||
grafana:
|
||||
container_name: grafana
|
||||
image: grafana/grafana:6.5.0
|
||||
image: grafana/grafana:6.5.2
|
||||
entrypoint: >
|
||||
/bin/sh -c "
|
||||
cd /var/lib/grafana &&
|
||||
|
||||
@@ -1,8 +1,14 @@
|
||||
## Case studies
|
||||
## Case studies and talks
|
||||
|
||||
Below are approved public case studies from VictoriaMetrics users. Join our [community Slack channel](http://slack.victoriametrics.com/)
|
||||
Below are approved public case studies and talks from VictoriaMetrics users. Join our [community Slack channel](http://slack.victoriametrics.com/)
|
||||
and feel free asking for references, reviews and additional case studies from real VictoriaMetrics users there.
|
||||
|
||||
### Adidas
|
||||
|
||||
See [slides](https://promcon.io/2019-munich/slides/remote-write-storage-wars.pdf) and [video](https://youtu.be/OsH6gPdxR4s)
|
||||
from [Remote Write Storage Wars](https://promcon.io/2019-munich/talks/remote-write-storage-wars/) talk at [PromCon 2019](https://promcon.io/2019-munich/).
|
||||
VictoriaMetrics is compared to Thanos, Corex and M3DB in the talk.
|
||||
|
||||
|
||||
### Wix.com
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
VictoriaMetrics is fast, cost-effective and scalable time series database. It can be used as a long-term remote storage for Prometheus.
|
||||
|
||||
It is recommended using [single-node version](https://github.com/VictoriaMetrics/VictoriaMetrics) instead of cluster version
|
||||
for ingestion rates lower than 10 million of data points per second.
|
||||
for ingestion rates lower than a million of data points per second.
|
||||
Single-node version [scales perfectly](https://medium.com/@valyala/measuring-vertical-scalability-for-time-series-databases-in-google-cloud-92550d78d8ae)
|
||||
with the number of CPU cores, RAM and available storage space.
|
||||
Single-node version is easier to configure and operate comparing to cluster version, so think twice before sticking to cluster version.
|
||||
@@ -133,6 +133,7 @@ with [the official Grafana dashboard for VictoriaMetrics cluster](https://grafan
|
||||
- `<suffix>` may have the following values:
|
||||
- `prometheus` - for inserting data with [Prometheus remote write API](https://prometheus.io/docs/prometheus/latest/configuration/configuration/#remote_write)
|
||||
- `influx/write` or `influx/api/v2/write` - for inserting data with [Influx line protocol](https://docs.influxdata.com/influxdb/v1.7/write_protocols/line_protocol_tutorial/)
|
||||
- `opentsdb/api/put` - for accepting [OpenTSDB HTTP /api/put requests](http://opentsdb.net/docs/build/html/api_http/put.html).
|
||||
- `prometheus/api/v1/import` - for importing data obtained via `api/v1/export` on `vmselect` (see below).
|
||||
|
||||
* URLs for querying: `http://<vmselect>:8481/select/<accountID>/prometheus/<suffix>`, where:
|
||||
|
||||
@@ -98,3 +98,10 @@ This functionality can be tried at [an editable Grafana dashboard](http://play-g
|
||||
Example: `share_le_over_time(memory_usage_bytes[24h], 100*1024*1024)` returns the share of time series values for the last 24 hours when memory usage was below or equal to 100MB.
|
||||
- `share_gt_over_time(m[d], gt)` - returns share (in the range 0..1) of values in `m` over `d`, which are bigger than `gt`. Useful for calculating SLI and SLO.
|
||||
Example: `share_gt_over_time(up[24h], 0)` - returns service availability for the last 24 hours.
|
||||
- `tmin_over_time(m[d])` - returns timestamp for the minimum value for `m` over `d` time range.
|
||||
- `tmax_over_time(m[d])` - returns timestamp for the maximum value for `m` over `d` time range.
|
||||
- `aggr_over_time(("aggr_func1", "aggr_func2", ...), m[d])` - simultaneously calculates all the listed `aggr_func*` for `m` over `d` time range.
|
||||
`aggr_func*` can contain any functions that accept range vector. For instance, `aggr_over_time(("min_over_time", "max_over_time", "rate"), m[d])`
|
||||
would calculate `min_over_time`, `max_over_time` and `rate` for `m[d]`.
|
||||
- `hoeffding_bound_upper(phi, m[d])` and `hoeffding_bound_lower(phi, m[d])` - return upper and lower [Hoeffding bounds](https://en.wikipedia.org/wiki/Hoeffding%27s_inequality)
|
||||
for the given `phi` in the range `[0..1]`.
|
||||
|
||||
59
docs/FAQ.md
59
docs/FAQ.md
@@ -16,7 +16,7 @@ To provide the best long-term [remote storage](https://prometheus.io/docs/operat
|
||||
* High data compression, so [up to 70x more data points](https://medium.com/@valyala/when-size-matters-benchmarking-victoriametrics-vs-timescale-and-influxdb-6035811952d4)
|
||||
may be crammed into a limited storage comparing to TimescaleDB.
|
||||
* Optimized for storage with high-latency IO and low iops (HDD and network storage in AWS, Google Cloud, Microsoft Azure, etc). See [graphs from these benchmarks](https://medium.com/@valyala/high-cardinality-tsdb-benchmarks-victoriametrics-vs-timescaledb-vs-influxdb-13e6ee64dd6b).
|
||||
* A single-node VictoriaMetrics may substitute moderately sized clusters built with competing solutions such as Thanos, Uber M3, Cortex, InfluxDB or TimescaleDB.
|
||||
* A single-node VictoriaMetrics may substitute moderately sized clusters built with competing solutions such as Thanos, M3DB, Cortex, InfluxDB or TimescaleDB.
|
||||
See [vertical scalability benchmarks](https://medium.com/@valyala/measuring-vertical-scalability-for-time-series-databases-in-google-cloud-92550d78d8ae)
|
||||
and [comparing Thanos to VictoriaMetrics](https://medium.com/@valyala/comparing-thanos-to-victoriametrics-cluster-b193bea1683).
|
||||
* Easy operation:
|
||||
@@ -54,14 +54,56 @@ Yes. Prometheus continues writing data to local storage after enabling remote st
|
||||
and new data is available for querying via Prometheus as usual.
|
||||
|
||||
|
||||
### How does VictoriaMetrics compare to other clustered TSDBs on top of Prometheus such as [M3 from Uber](https://eng.uber.com/m3/), [Thanos](https://github.com/improbable-eng/thanos), [Cortex](https://github.com/cortexproject/cortex), etc.?
|
||||
### How does VictoriaMetrics compare to other clustered TSDBs on top of Prometheus such as [M3 from Uber](https://eng.uber.com/m3/), [Thanos](https://github.com/thanos-io/thanos), [Cortex](https://github.com/cortexproject/cortex), etc.?
|
||||
|
||||
VictoriaMetrics is simpler, faster, more cost-effective and it provides [useful extensions for PromQL](ExtendedPromQL). The simplicity is twofold:
|
||||
- It is simpler to configure and operate. There is no need in configuring third-party [sidecars](https://github.com/improbable-eng/thanos/blob/master/docs/components/sidecar.md)
|
||||
or fighting with [gossip protocol](https://github.com/improbable-eng/thanos/blob/master/docs/proposals/completed/201809_gossip-removal.md).
|
||||
- VictoriaMetrics has simpler architecture, which means less bugs and more useful features in a long run comparing to competing TSDBs.
|
||||
VictoriaMetrics is simpler, faster, more cost-effective and it provides [MetricsQL with useful extensions for PromQL](ExtendedPromQL). The simplicity is twofold:
|
||||
- It is simpler to configure and operate. There is no need in configuring third-party [sidecars](https://github.com/thanos-io/thanos/blob/master/docs/components/sidecar.md)
|
||||
or fighting with [gossip protocol](https://github.com/thanos-io/thanos/blob/master/docs/proposals/completed/201809_gossip-removal.md).
|
||||
- VictoriaMetrics has simpler architecture, which means less bugs and more useful features in the long run comparing to competing TSDBs.
|
||||
|
||||
See [comparing Thanos to VictoriaMetrics cluster](https://medium.com/@valyala/comparing-thanos-to-victoriametrics-cluster-b193bea1683).
|
||||
See [comparing Thanos to VictoriaMetrics cluster](https://medium.com/@valyala/comparing-thanos-to-victoriametrics-cluster-b193bea1683)
|
||||
and [Remote Write Storage Wars](https://promcon.io/2019-munich/talks/remote-write-storage-wars/) talk from [PromCon 2019](https://promcon.io/2019-munich/talks/remote-write-storage-wars/).
|
||||
|
||||
VictoriaMetrics also [uses less RAM than Thanos components](https://github.com/thanos-io/thanos/issues/448).
|
||||
|
||||
|
||||
### What is the difference between VictoriaMetrics and [Cortex](https://github.com/cortexproject/cortex)?
|
||||
|
||||
VictoriaMetrics is similar to Cortex in the following aspects:
|
||||
- Both systems accept data from Prometheus via standard [remote_write API](https://prometheus.io/docs/practices/remote_write/),
|
||||
i.e. there is no need in running sidecars unlike in [Thanos](https://github.com/thanos-io/thanos) case.
|
||||
- Both systems support multi-tenancy out of the box. See [the corresponding docs for VictoriaMetrics](https://github.com/VictoriaMetrics/VictoriaMetrics/blob/cluster/README.md#url-format).
|
||||
|
||||
The main differences between Corex and VictoriaMetrics:
|
||||
- Cortex re-uses Prometheus source code, while VictoriaMetrics is written from scratch.
|
||||
- Cortex provides [Ruler](https://github.com/cortexproject/cortex/blob/master/docs/architecture.md#ruler) and [Alertmanager](https://github.com/cortexproject/cortex/blob/master/docs/architecture.md#alertmanager) components,
|
||||
which are currently missing in VictoriaMetrics. However, these components can be substituted by [Promxy](https://github.com/jacksontj/promxy#how-do-i-use-alertingrecording-rules-in-promxy).
|
||||
- Cortex heavily relies on third-party services such as Consul, Memcache, DynamoDB, BigTable, Cassandra, etc.
|
||||
This may increase operational complexity and reduce system reliability comparing to VictoriaMetrics' case,
|
||||
which doesn't use any external services. Compare [Cortex Architecture](https://github.com/cortexproject/cortex/blob/master/docs/architecture.md)
|
||||
to [VictoriaMetrics architecture](https://github.com/VictoriaMetrics/VictoriaMetrics/blob/cluster/README.md#architecture-overview).
|
||||
- VictoriaMetrics provides [production-ready single-node solution](https://github.com/VictoriaMetrics/VictoriaMetrics/blob/master/README.md),
|
||||
which is much easier to setup and operate than Cortex cluster.
|
||||
- Cortex may lose up to 12 hours of recent data on Ingestor failure - see [the corresponding docs](https://github.com/cortexproject/cortex/blob/master/docs/architecture.md#ingesters-failure-and-data-loss).
|
||||
VictoriaMetrics may lose only a few seconds of recent data, which isn't synced to persistent storage yet.
|
||||
See [this article for details](https://medium.com/@valyala/wal-usage-looks-broken-in-modern-time-series-databases-b62a627ab704).
|
||||
- Cortex is usually slower and requires more CPU and RAM than VictoriaMetrics. See [this talk from Adidas at PromCon 2019](https://promcon.io/2019-munich/talks/remote-write-storage-wars/).
|
||||
|
||||
|
||||
### What is the difference between VictoriaMetrics and [Thanos](https://github.com/thanos-io/thanos)?
|
||||
|
||||
- Thanos re-uses Prometheus source code, while VictoriaMetrics is written from scratch.
|
||||
- Thanos provides [Ruler component](https://github.com/thanos-io/thanos/blob/master/docs/components/rule.md),
|
||||
while VictoriaMetrics relies on [Promxy for alerting and recording rules](https://github.com/jacksontj/promxy#how-do-i-use-alertingrecording-rules-in-promxy).
|
||||
- VictoriaMetrics accepts data via [standard remote_write API for Prometheus](https://prometheus.io/docs/practices/remote_write/),
|
||||
while Thanos uses non-standard [Sidecar](https://github.com/thanos-io/thanos/blob/master/docs/components/sidecar.md), which must run alongside each Prometheus instance.
|
||||
- Thanos Sidecar requires disabling data compaction in Prometheus, which may hurt Prometheus performance and increase RAM usage.
|
||||
- Thanos stores data on object storage (Amazon S3 or Google GCS), while VictoriaMetrics stores data on block storage (GCP persistent disks, Amazon EBS or bare metal HDD).
|
||||
- Thanos may lose up to 2 hours of recent data, which wasn't uploaded yet to object storage. VictoriaMetrics may lose only a few seconds of recent data,
|
||||
which isn't synced to persistent storage yet. See [this article for details](https://medium.com/@valyala/wal-usage-looks-broken-in-modern-time-series-databases-b62a627ab704).
|
||||
- Thanos may be harder to setup and operate comparing to VictoriaMetrics, since it has more moving parts, which can be connected with less reliable networks.
|
||||
See [this article for details](https://medium.com/faun/comparing-thanos-to-victoriametrics-cluster-b193bea1683).
|
||||
- Thanos is usually slower and requires more CPU and RAM than VictoriaMetrics. See [this talk from Adidas at PromCon 2019](https://promcon.io/2019-munich/talks/remote-write-storage-wars/).
|
||||
|
||||
|
||||
### How does VictoriaMetrics compare to [InfluxDB](https://www.influxdata.com/time-series-platform/influxdb/)?
|
||||
@@ -76,12 +118,13 @@ TimescaleDB insists on using SQL as a query language. While SQL is more powerful
|
||||
Additionally, VictoriaMetrics requires [up to 70x less storage space comparing to TimescaleDB](https://medium.com/@valyala/when-size-matters-benchmarking-victoriametrics-vs-timescale-and-influxdb-6035811952d4) for storing the same amount of time series data.
|
||||
|
||||
|
||||
### Does VictoriaMetrics use Prometheus technologies like other clustered TSDBs built on top of Prometheus such as [M3 from Uber](https://eng.uber.com/m3/), [Thanos](https://github.com/improbable-eng/thanos), [Cortex](https://github.com/cortexproject/cortex)?
|
||||
### Does VictoriaMetrics use Prometheus technologies like other clustered TSDBs built on top of Prometheus such as [M3 from Uber](https://eng.uber.com/m3/), [Thanos](https://github.com/thanos-io/thanos), [Cortex](https://github.com/cortexproject/cortex)?
|
||||
|
||||
No. VictoriaMetrics core is written in Go from scratch by [fasthttp](https://github.com/valyala/fasthttp) [author](https://github.com/valyala).
|
||||
The architecture is [optimized for storing and querying large amounts of time series data with high cardinality](https://medium.com/devopslinks/victoriametrics-creating-the-best-remote-storage-for-prometheus-5d92d66787ac). VictoriaMetrics storage uses [certain ideas from ClickHouse](https://medium.com/@valyala/how-victoriametrics-makes-instant-snapshots-for-multi-terabyte-time-series-data-e1f3fb0e0282). Special thanks to [Alexey Milovidov](https://github.com/alexey-milovidov).
|
||||
|
||||
|
||||
|
||||
### Are there performance comparisons with other solutions?
|
||||
|
||||
Yes:
|
||||
|
||||
@@ -28,9 +28,11 @@ Cluster version is available [here](https://github.com/VictoriaMetrics/VictoriaM
|
||||
* High data compression, so [up to 70x more data points](https://medium.com/@valyala/when-size-matters-benchmarking-victoriametrics-vs-timescale-and-influxdb-6035811952d4)
|
||||
may be crammed into limited storage comparing to TimescaleDB.
|
||||
* Optimized for storage with high-latency IO and low IOPS (HDD and network storage in AWS, Google Cloud, Microsoft Azure, etc). See [graphs from these benchmarks](https://medium.com/@valyala/high-cardinality-tsdb-benchmarks-victoriametrics-vs-timescaledb-vs-influxdb-13e6ee64dd6b).
|
||||
* A single-node VictoriaMetrics may substitute moderately sized clusters built with competing solutions such as Thanos, Uber M3, Cortex, InfluxDB or TimescaleDB.
|
||||
See [vertical scalability benchmarks](https://medium.com/@valyala/measuring-vertical-scalability-for-time-series-databases-in-google-cloud-92550d78d8ae)
|
||||
and [comparing Thanos to VictoriaMetrics cluster](https://medium.com/@valyala/comparing-thanos-to-victoriametrics-cluster-b193bea1683).
|
||||
* A single-node VictoriaMetrics may substitute moderately sized clusters built with competing solutions such as Thanos, M3DB, Cortex, InfluxDB or TimescaleDB.
|
||||
See [vertical scalability benchmarks](https://medium.com/@valyala/measuring-vertical-scalability-for-time-series-databases-in-google-cloud-92550d78d8ae),
|
||||
[comparing Thanos to VictoriaMetrics cluster](https://medium.com/@valyala/comparing-thanos-to-victoriametrics-cluster-b193bea1683)
|
||||
and [Remote Write Storage Wars](https://promcon.io/2019-munich/talks/remote-write-storage-wars/) talk
|
||||
from [PromCon 2019](https://promcon.io/2019-munich/talks/remote-write-storage-wars/).
|
||||
* Easy operation:
|
||||
* VictoriaMetrics consists of a single [small executable](https://medium.com/@valyala/stripping-dependency-bloat-in-victoriametrics-docker-image-983fb5912b0d) without external dependencies.
|
||||
* All the configuration is done via explicit command-line flags with reasonable defaults.
|
||||
@@ -491,6 +493,7 @@ Read [these instructions](https://github.com/VictoriaMetrics/VictoriaMetrics/iss
|
||||
### Third-party contributions
|
||||
|
||||
* [Unofficial yum repository](https://copr.fedorainfracloud.org/coprs/antonpatsev/VictoriaMetrics/) ([source code](https://github.com/patsevanton/victoriametrics-rpm))
|
||||
* [Prometheus -> VictoriaMetrics exporter](https://github.com/ryotarai/prometheus-tsdb-dump)
|
||||
|
||||
|
||||
### How to work with snapshots?
|
||||
@@ -615,7 +618,7 @@ A rough estimation of the required resources for ingestion path:
|
||||
* RAM size: less than 1KB per active time series. So, ~1GB of RAM is required for 1M active time series.
|
||||
Time series is considered active if new data points have been added to it recently or if it has been recently queried.
|
||||
The number of active time series may be obtained from `vm_cache_entries{type="storage/hour_metric_ids"}` metric
|
||||
exproted on the `/metrics` page.
|
||||
exported on the `/metrics` page.
|
||||
VictoriaMetrics stores various caches in RAM. Memory size for these caches may be limited by `-memory.allowedPercent` flag.
|
||||
|
||||
* CPU cores: a CPU core per 300K inserted data points per second. So, ~4 CPU cores are required for processing
|
||||
@@ -696,7 +699,7 @@ There is no downsampling support at the moment, but:
|
||||
- VictoriaMetrics has good compression for on-disk data. See [this article](https://medium.com/@valyala/victoriametrics-achieving-better-compression-for-time-series-data-than-gorilla-317bc1f95932)
|
||||
for details.
|
||||
|
||||
These properties reduce the need in downsampling. We plan to implement downsampling in the future.
|
||||
These properties reduce the need of downsampling. We plan to implement downsampling in the future.
|
||||
See [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/36) for details.
|
||||
|
||||
|
||||
@@ -741,14 +744,14 @@ For example, substitute `-graphiteListenAddr=:2003` with `-graphiteListenAddr=<i
|
||||
|
||||
### Tuning
|
||||
|
||||
* There is no need in VictoriaMetrics tuning since it uses reasonable defaults for command-line flags,
|
||||
* There is no need for VictoriaMetrics tuning since it uses reasonable defaults for command-line flags,
|
||||
which are automatically adjusted for the available CPU and RAM resources.
|
||||
* There is no need in Operating System tuning since VictoriaMetrics is optimized for default OS settings.
|
||||
* There is no need for Operating System tuning since VictoriaMetrics is optimized for default OS settings.
|
||||
The only option is increasing the limit on [the number of open files in the OS](https://medium.com/@muhammadtriwibowo/set-permanently-ulimit-n-open-files-in-ubuntu-4d61064429a),
|
||||
so Prometheus instances could establish more connections to VictoriaMetrics.
|
||||
* The recommended filesystem is `ext4`, the recommended persistent storage is [persistent HDD-based disk on GCP](https://cloud.google.com/compute/docs/disks/#pdspecs),
|
||||
since it is protected from hardware failures via internal replication and it can be [resized on the fly](https://cloud.google.com/compute/docs/disks/add-persistent-disk#resize_pd).
|
||||
If you plan storing more than 1TB of data on `ext4` partition or plan extending it to more than 16TB,
|
||||
If you plan to store more than 1TB of data on `ext4` partition or plan extending it to more than 16TB,
|
||||
then the following options are recommended to pass to `mkfs.ext4`:
|
||||
|
||||
```
|
||||
@@ -779,7 +782,7 @@ The most interesting metrics are:
|
||||
### Troubleshooting
|
||||
|
||||
* It is recommended to use default command-line flag values (i.e. don't set them explicitly) until the need
|
||||
in tweaking these flag values arises.
|
||||
of tweaking these flag values arises.
|
||||
|
||||
* If VictoriaMetrics works slowly and eats more than a CPU core per 100K ingested data points per second,
|
||||
then it is likely you have too many active time series for the current amount of RAM.
|
||||
@@ -793,7 +796,7 @@ The most interesting metrics are:
|
||||
has at least 20% of free space comparing to disk size.
|
||||
|
||||
* If VictoriaMetrics doesn't work because of certain parts are corrupted due to disk errors,
|
||||
then just remove directoreis with broken parts. This will recover VictoriaMetrics at the cost
|
||||
then just remove directories with broken parts. This will recover VictoriaMetrics at the cost
|
||||
of data loss stored in the broken parts. In the future, `vmrecover` tool will be created
|
||||
for automatic recovering from such errors.
|
||||
|
||||
@@ -844,7 +847,7 @@ The collected profiles may be analyzed with [go tool pprof](https://github.com/g
|
||||
- [ ] CLI tool for data migration, re-balancing and adding/removing nodes [#103](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/103)
|
||||
|
||||
|
||||
The discussion happens [here](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/129). Feel free to comment any item or add own one.
|
||||
The discussion happens [here](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/129). Feel free to comment on any item or add you own one.
|
||||
|
||||
|
||||
## Contacts
|
||||
@@ -857,6 +860,7 @@ Contact us with any questions regarding VictoriaMetrics at [info@victoriametrics
|
||||
Feel free asking any questions regarding VictoriaMetrics:
|
||||
|
||||
- [slack](http://slack.victoriametrics.com/)
|
||||
- [reddit](https://www.reddit.com/r/VictoriaMetrics/)
|
||||
- [telegram-en](https://t.me/VictoriaMetrics_en)
|
||||
- [telegram-ru](https://t.me/VictoriaMetrics_ru1)
|
||||
- [google groups](https://groups.google.com/forum/#!forum/victorametrics-users)
|
||||
@@ -887,7 +891,7 @@ Report bugs and propose new features [here](https://github.com/VictoriaMetrics/V
|
||||
|
||||
## Victoria Metrics Logo
|
||||
|
||||
[Zip](VM_logo.zip) contains three folders with different image orientation (main color and inverted version).
|
||||
[Zip](VM_logo.zip) contains three folders with different image orientations (main color and inverted version).
|
||||
|
||||
Files included in each folder:
|
||||
|
||||
|
||||
26
go.mod
26
go.mod
@@ -1,31 +1,25 @@
|
||||
module github.com/VictoriaMetrics/VictoriaMetrics
|
||||
|
||||
require (
|
||||
cloud.google.com/go v0.50.0 // indirect
|
||||
cloud.google.com/go/storage v1.4.0
|
||||
cloud.google.com/go v0.51.0 // indirect
|
||||
cloud.google.com/go/storage v1.5.0
|
||||
github.com/VictoriaMetrics/fastcache v1.5.5
|
||||
github.com/VictoriaMetrics/metrics v1.9.3
|
||||
github.com/aws/aws-sdk-go v1.26.8
|
||||
github.com/aws/aws-sdk-go v1.28.3
|
||||
github.com/cespare/xxhash/v2 v2.1.1
|
||||
github.com/golang/groupcache v0.0.0-20191027212112-611e8accdfc9 // indirect
|
||||
github.com/golang/snappy v0.0.1
|
||||
github.com/jstemmer/go-junit-report v0.9.1 // indirect
|
||||
github.com/klauspost/compress v1.9.4
|
||||
github.com/valyala/fastjson v1.4.1
|
||||
github.com/klauspost/compress v1.9.7
|
||||
github.com/valyala/fastjson v1.4.5
|
||||
github.com/valyala/fastrand v1.0.0
|
||||
github.com/valyala/gozstd v1.6.4
|
||||
github.com/valyala/histogram v1.0.1
|
||||
github.com/valyala/quicktemplate v1.4.1
|
||||
go.opencensus.io v0.22.2 // indirect
|
||||
golang.org/x/exp v0.0.0-20191224044220-1fea468a75e9 // indirect
|
||||
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553 // indirect
|
||||
golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6 // indirect
|
||||
golang.org/x/sys v0.0.0-20191224085550-c709ea063b76
|
||||
golang.org/x/tools v0.0.0-20191224055732-dd894d0a8a40 // indirect
|
||||
golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa // indirect
|
||||
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d // indirect
|
||||
golang.org/x/sys v0.0.0-20200116001909-b77594299b42
|
||||
golang.org/x/tools v0.0.0-20200116062425-473961ec044c // indirect
|
||||
google.golang.org/api v0.15.0
|
||||
google.golang.org/appengine v1.6.5 // indirect
|
||||
google.golang.org/genproto v0.0.0-20191223191004-3caeed10a8bf // indirect
|
||||
google.golang.org/grpc v1.26.0 // indirect
|
||||
google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba // indirect
|
||||
)
|
||||
|
||||
go 1.12
|
||||
|
||||
73
go.sum
73
go.sum
@@ -5,17 +5,20 @@ cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6A
|
||||
cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
|
||||
cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=
|
||||
cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=
|
||||
cloud.google.com/go v0.50.0 h1:0E3eE8MX426vUOs7aHfI7aN1BrIzzzf4ccKCSfSjGmc=
|
||||
cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To=
|
||||
cloud.google.com/go/bigquery v1.0.1 h1:hL+ycaJpVE9M7nLoiXb/Pn10ENE2u+oddxbD8uu0ZVU=
|
||||
cloud.google.com/go v0.51.0 h1:PvKAVQWCtlGUSlZkGW3QLelKaWq7KYv/MW1EboG8bfM=
|
||||
cloud.google.com/go v0.51.0/go.mod h1:hWtGJ6gnXH+KgDv+V0zFGDvpi07n3z8ZNj3T1RW0Gcw=
|
||||
cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
|
||||
cloud.google.com/go/bigquery v1.3.0 h1:sAbMqjY1PEQKZBWfbu6Y6bsupJ9c4QdHnzg/VvYTLcE=
|
||||
cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
|
||||
cloud.google.com/go/datastore v1.0.0 h1:Kt+gOPPp2LEPWp8CSfxhsM8ik9CcyE/gYu+0r+RnZvM=
|
||||
cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
|
||||
cloud.google.com/go/pubsub v1.0.1 h1:W9tAK3E57P75u0XLLR82LZyw8VpAnhmyTOxW9qzmyj8=
|
||||
cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
|
||||
cloud.google.com/go/pubsub v1.1.0 h1:9/vpR43S4aJaROxqQHQ3nH9lfyKKV0dC3vOmnw8ebQQ=
|
||||
cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=
|
||||
cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
|
||||
cloud.google.com/go/storage v1.4.0 h1:KDdqY5VTXBTqpSbctVTt0mVvfanP6JZzNzLE0qNY100=
|
||||
cloud.google.com/go/storage v1.4.0/go.mod h1:ZusYJWlOshgSBGbt6K3GnB3MT3H1xs2id9+TCl4fDBA=
|
||||
cloud.google.com/go/storage v1.5.0 h1:RPUcBvDeYgQFMfQu1eBMq6piD1SXmLH+vK3qjewZPus=
|
||||
cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos=
|
||||
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
|
||||
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
@@ -26,11 +29,14 @@ github.com/VictoriaMetrics/metrics v1.9.3 h1:+1kZnOIb8RY825Nb9q9yMrPcOYuPE2GrZWx
|
||||
github.com/VictoriaMetrics/metrics v1.9.3/go.mod h1:LU2j9qq7xqZYXz8tF3/RQnB2z2MbZms5TDiIg9/NHiQ=
|
||||
github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156 h1:eMwmnE/GDgah4HI848JfFxHt+iPb26b4zyfspmqY0/8=
|
||||
github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM=
|
||||
github.com/aws/aws-sdk-go v1.26.8 h1:W+MPuCFLSO/itZkZ5GFOui0YC1j3lZ507/m5DFPtzE4=
|
||||
github.com/aws/aws-sdk-go v1.26.8/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
|
||||
github.com/aws/aws-sdk-go v1.28.3 h1:FnkDp+fz4JHWUW3Ust2Wh89RpdGif077Wjis/sMrGKM=
|
||||
github.com/aws/aws-sdk-go v1.28.3/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
|
||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||
github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY=
|
||||
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
|
||||
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
|
||||
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
@@ -42,8 +48,8 @@ github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20191027212112-611e8accdfc9 h1:uHTyIjqVhYRhLbJ8nIiOJHkEZZ+5YoOsAbD3sk82NiE=
|
||||
github.com/golang/groupcache v0.0.0-20191027212112-611e8accdfc9/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7 h1:5ZkaAPbicIKTF2I64qf5Fh8Aa83Q/dnOafMYV0OMwjA=
|
||||
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
|
||||
@@ -56,18 +62,21 @@ github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEW
|
||||
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||
github.com/google/go-cmp v0.3.0 h1:crn/baboCvb5fXaQ0IJ1SGTsTVrWpDsCWC8EGETZijY=
|
||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.3.1 h1:Xye71clBPdm5HgqGwUkwhbynsUJZhDbS20FvLhQ2izg=
|
||||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/martian v2.1.0+incompatible h1:/CP5g8u/VJHijgedC/Legn3BAbAaWPgecwXBIDzw5no=
|
||||
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
|
||||
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||
github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||
github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
|
||||
github.com/googleapis/gax-go/v2 v2.0.5 h1:sjZBwGj9Jlw33ImPtvFviGYvseOtDM7hkSKB7+Tv3SM=
|
||||
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
|
||||
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af h1:pmfjZENx5imkbgOkpRUYLnmbU7UEFbjtDA2hxJ1ichM=
|
||||
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
|
||||
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
||||
@@ -76,8 +85,8 @@ github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/X
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/klauspost/compress v1.4.0/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
|
||||
github.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
|
||||
github.com/klauspost/compress v1.9.4 h1:xhvAeUPQ2drNUhKtrGdTGNvV9nNafHMUkRyLkzxJoB4=
|
||||
github.com/klauspost/compress v1.9.4/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
|
||||
github.com/klauspost/compress v1.9.7 h1:hYW1gP94JUmAhBtJ+LNz5My+gBobDxPR1iVuKug26aA=
|
||||
github.com/klauspost/compress v1.9.7/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
|
||||
github.com/klauspost/cpuid v0.0.0-20180405133222-e7e905edc00e/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
|
||||
github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
|
||||
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
|
||||
@@ -90,15 +99,14 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN
|
||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
|
||||
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
|
||||
github.com/valyala/fasthttp v1.2.0/go.mod h1:4vX61m6KN+xDduDNwXrhIAVZaZaZiQ1luJk8LWSxF3s=
|
||||
github.com/valyala/fastjson v1.4.1 h1:hrltpHpIpkaxll8QltMU8c3QZ5+qIiCL8yKqPFJI/yE=
|
||||
github.com/valyala/fastjson v1.4.1/go.mod h1:nV6MsjxL2IMJQUoHDIrjEI7oLyeqK6aBD7EFWPsvP8o=
|
||||
github.com/valyala/fastjson v1.4.5 h1:uSuLfXk2LzRtzwd3Fy5zGRBe0Vs7zhs11vjdko32xb4=
|
||||
github.com/valyala/fastjson v1.4.5/go.mod h1:nV6MsjxL2IMJQUoHDIrjEI7oLyeqK6aBD7EFWPsvP8o=
|
||||
github.com/valyala/fastrand v1.0.0 h1:LUKT9aKer2dVQNUi3waewTbKV+7H17kvWFNKs2ObdkI=
|
||||
github.com/valyala/fastrand v1.0.0/go.mod h1:HWqCzkrkg6QXT8V2EXWvXCoow7vLwOFN002oeRzjapQ=
|
||||
github.com/valyala/gozstd v1.6.4 h1:nFLddjEf90SFl5cVWyElSHozQDsbvLljPK703/skBS0=
|
||||
@@ -120,12 +128,10 @@ golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL
|
||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||
golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=
|
||||
golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136 h1:A1gGSx58LAGVHUUsOf7IiR0u8Xb6W51gRwfDBhkdcaw=
|
||||
golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=
|
||||
golang.org/x/exp v0.0.0-20191129062945-2f5052295587 h1:5Uz0rkjCFu9BC9gCRN7EkwVvhNyQgGWb8KNJrPwBoHY=
|
||||
golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
|
||||
golang.org/x/exp v0.0.0-20191224044220-1fea468a75e9 h1:HLuLY2KniBsHW28uXd1i2UZKjifeJUy//P/wTK6AJwI=
|
||||
golang.org/x/exp v0.0.0-20191224044220-1fea468a75e9/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
|
||||
golang.org/x/exp v0.0.0-20191227195350-da58074b4299 h1:zQpM52jfKHG6II1ISZY1ZcpygvuSFZpLwfluuF89XOg=
|
||||
golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
|
||||
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
||||
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
@@ -134,7 +140,6 @@ golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTk
|
||||
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20190930215403-16217165b5de h1:5hukYrvBGR8/eNkX5mdUezrA6JiaEZDtJb9Ei+1LlBs=
|
||||
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f h1:J5lckAjkw6qYlOZNj90mLYNTEKDvWeuc1yieZ8qUzUE=
|
||||
golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=
|
||||
@@ -155,19 +160,19 @@ golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn
|
||||
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553 h1:efeOvDhwQ29Dj3SdAV/MJf8oukgn+8D8WgaCaRMchF8=
|
||||
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa h1:F+8P+gmewFQYRk6JoLQLwjBCTu3mcIURZfNkVweuRKA=
|
||||
golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45 h1:SVwTIAaPC2U/AvvLNZ2a7OVsmBpC8L5BlwK1whH3hm0=
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6 h1:pE8b58s1HRDMi8RDc79m0HISf9D4TzseP40cEA6IGfs=
|
||||
golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d h1:TzXSXBo42m9gQenoE3b9BGiEpg5IG2JkU5FkPIawgtw=
|
||||
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58 h1:8gQV6CLnAEikrhgkHFbMAEhagSSnXWGV915qUMm9mrU=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e h1:vcxGaoTs7kV8m5Np9uUNQin4BrLOthgV7252N8V+FwY=
|
||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
@@ -180,8 +185,10 @@ golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191224085550-c709ea063b76 h1:Dho5nD6R3PcW2SH1or8vS0dszDaXRxIw55lBX7XiE5g=
|
||||
golang.org/x/sys v0.0.0-20191224085550-c709ea063b76/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200116001909-b77594299b42 h1:vEOn+mP2zCOVzKckCZy6YsCtDblrpj/w7B9nxGNELpg=
|
||||
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
|
||||
@@ -203,18 +210,20 @@ golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgw
|
||||
golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20191224055732-dd894d0a8a40 h1:UyP2XDSgSc8ldYCxAK735zQxeH3Gd81sK7Iy7AoaVxk=
|
||||
golang.org/x/tools v0.0.0-20191224055732-dd894d0a8a40/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200116062425-473961ec044c h1:D0OxfnjPaEGt7AluXNompYUYGhoY3u6+bValgqfd1vE=
|
||||
golang.org/x/tools v0.0.0-20200116062425-473961ec044c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
|
||||
google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
|
||||
google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
|
||||
google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
|
||||
google.golang.org/api v0.14.0 h1:uMf5uLi4eQMRrMKhCplNik4U4H8Z6C1br3zOtAa/aDE=
|
||||
google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
|
||||
google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
|
||||
google.golang.org/api v0.15.0 h1:yzlyyDW/J0w8yNFJIhiAJy4kq74S+1DOLdawELNxFMA=
|
||||
google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
|
||||
@@ -232,10 +241,12 @@ google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRn
|
||||
google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||
google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
|
||||
google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20191223191004-3caeed10a8bf h1:1x8rC5/IgdLMPbPTvlQTN28+rcy8XL9Q19UWUMDyqYs=
|
||||
google.golang.org/genproto v0.0.0-20191223191004-3caeed10a8bf/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba h1:pRj9OXZbwNtbtZtOB4dLwfK4u+EVRMvP+e9zKkg2grM=
|
||||
google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
|
||||
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/VictoriaMetrics/VictoriaMetrics/lib/backup/common"
|
||||
"github.com/VictoriaMetrics/VictoriaMetrics/lib/backup/fscommon"
|
||||
"github.com/VictoriaMetrics/VictoriaMetrics/lib/backup/fslocal"
|
||||
"github.com/VictoriaMetrics/VictoriaMetrics/lib/backup/fsnil"
|
||||
"github.com/VictoriaMetrics/VictoriaMetrics/lib/logger"
|
||||
@@ -41,17 +42,33 @@ type Backup struct {
|
||||
|
||||
// Run runs b with the provided settings.
|
||||
func (b *Backup) Run() error {
|
||||
startTime := time.Now()
|
||||
|
||||
concurrency := b.Concurrency
|
||||
src := b.Src
|
||||
dst := b.Dst
|
||||
origin := b.Origin
|
||||
|
||||
if origin != nil && origin.String() == dst.String() {
|
||||
origin = nil
|
||||
}
|
||||
if origin == nil {
|
||||
origin = &fsnil.FS{}
|
||||
}
|
||||
|
||||
if err := dst.DeleteFile(fscommon.BackupCompleteFilename); err != nil {
|
||||
return fmt.Errorf("cannot delete `backup complete` file at %s: %s", dst, err)
|
||||
}
|
||||
if err := runBackup(src, dst, origin, concurrency); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := dst.CreateFile(fscommon.BackupCompleteFilename, []byte("ok")); err != nil {
|
||||
return fmt.Errorf("cannot create `backup complete` file at %s: %s", dst, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func runBackup(src *fslocal.FS, dst common.RemoteFS, origin common.OriginFS, concurrency int) error {
|
||||
startTime := time.Now()
|
||||
|
||||
logger.Infof("starting backup from %s to %s using origin %s", src, dst, origin)
|
||||
|
||||
logger.Infof("obtaining list of parts at %s", src)
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/VictoriaMetrics/VictoriaMetrics/lib/backup/common"
|
||||
"github.com/VictoriaMetrics/VictoriaMetrics/lib/backup/fscommon"
|
||||
"github.com/VictoriaMetrics/VictoriaMetrics/lib/backup/fslocal"
|
||||
"github.com/VictoriaMetrics/VictoriaMetrics/lib/fs"
|
||||
"github.com/VictoriaMetrics/VictoriaMetrics/lib/logger"
|
||||
@@ -29,6 +30,11 @@ type Restore struct {
|
||||
// If dst points to existing directory, then incremental restore is performed,
|
||||
// i.e. only new data is downloaded from src.
|
||||
Dst *fslocal.FS
|
||||
|
||||
// SkipBackupCompleteCheck may be set in order to skip for `backup complete` file in Src.
|
||||
//
|
||||
// This may be needed for restoring from old backups with missing `backup complete` file.
|
||||
SkipBackupCompleteCheck bool
|
||||
}
|
||||
|
||||
// Run runs r with the provided settings.
|
||||
@@ -48,6 +54,18 @@ func (r *Restore) Run() error {
|
||||
concurrency := r.Concurrency
|
||||
src := r.Src
|
||||
dst := r.Dst
|
||||
|
||||
if !r.SkipBackupCompleteCheck {
|
||||
ok, err := src.HasFile(fscommon.BackupCompleteFilename)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !ok {
|
||||
return fmt.Errorf("cannot find %s file in %s; this means either incomplete backup or old backup; "+
|
||||
"pass `-skipBackupCompleteCheck` command-line flag if you still need restoring from this backup", fscommon.BackupCompleteFilename, src)
|
||||
}
|
||||
}
|
||||
|
||||
logger.Infof("starting restore from %s to %s", src, dst)
|
||||
|
||||
logger.Infof("obtaining list of parts at %s", src)
|
||||
|
||||
@@ -38,4 +38,13 @@ type RemoteFS interface {
|
||||
|
||||
// UploadPart must upload part p from r to RemoteFS.
|
||||
UploadPart(p Part, r io.Reader) error
|
||||
|
||||
// DeleteFile deletes filePath at RemoteFS
|
||||
DeleteFile(filePath string) error
|
||||
|
||||
// CreateFile creates filePath at RemoteFS and puts data into it.
|
||||
CreateFile(filePath string, data []byte) error
|
||||
|
||||
// HasFile returns true if filePath exists at RemoteFS.
|
||||
HasFile(filePath string) (bool, error)
|
||||
}
|
||||
|
||||
@@ -260,3 +260,11 @@ func removeEmptyDirsInternal(d *os.File) (bool, error) {
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// IgnorePath returns true if the given path must be ignored.
|
||||
func IgnorePath(path string) bool {
|
||||
return strings.HasSuffix(path, ".ignore")
|
||||
}
|
||||
|
||||
// BackupCompleteFilename is a filename, which is created in the destination fs when backup is complete.
|
||||
const BackupCompleteFilename = "backup_complete.ignore"
|
||||
|
||||
@@ -3,6 +3,7 @@ package fsremote
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
@@ -48,6 +49,9 @@ func (fs *FS) ListParts() ([]common.Part, error) {
|
||||
if !strings.HasPrefix(file, dir) {
|
||||
logger.Panicf("BUG: unexpected prefix for file %q; want %q", file, dir)
|
||||
}
|
||||
if fscommon.IgnorePath(file) {
|
||||
continue
|
||||
}
|
||||
var p common.Part
|
||||
if !p.ParseFromRemotePath(file[len(dir):]) {
|
||||
logger.Infof("skipping unknown file %s", file)
|
||||
@@ -188,3 +192,42 @@ func (fs *FS) mkdirAll(filePath string) error {
|
||||
func (fs *FS) path(p common.Part) string {
|
||||
return p.RemotePath(fs.Dir)
|
||||
}
|
||||
|
||||
// DeleteFile deletes filePath at fs.
|
||||
//
|
||||
// The function does nothing if the filePath doesn't exist.
|
||||
func (fs *FS) DeleteFile(filePath string) error {
|
||||
path := filepath.Join(fs.Dir, filePath)
|
||||
err := os.Remove(path)
|
||||
if err != nil && !os.IsNotExist(err) {
|
||||
return fmt.Errorf("cannot remove %q: %s", path, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// CreateFile creates filePath at fs and puts data into it.
|
||||
//
|
||||
// The file is overwritten if it exists.
|
||||
func (fs *FS) CreateFile(filePath string, data []byte) error {
|
||||
path := filepath.Join(fs.Dir, filePath)
|
||||
if err := ioutil.WriteFile(path, data, 0600); err != nil {
|
||||
return fmt.Errorf("cannot write %d bytes to %q: %s", len(data), path, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// HasFile returns true if filePath exists at fs.
|
||||
func (fs *FS) HasFile(filePath string) (bool, error) {
|
||||
path := filepath.Join(fs.Dir, filePath)
|
||||
fi, err := os.Stat(path)
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
return false, nil
|
||||
}
|
||||
return false, fmt.Errorf("cannot stat %q: %s", path, err)
|
||||
}
|
||||
if fi.IsDir() {
|
||||
return false, fmt.Errorf("%q is directory, while file is needed", path)
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
|
||||
"cloud.google.com/go/storage"
|
||||
"github.com/VictoriaMetrics/VictoriaMetrics/lib/backup/common"
|
||||
"github.com/VictoriaMetrics/VictoriaMetrics/lib/backup/fscommon"
|
||||
"github.com/VictoriaMetrics/VictoriaMetrics/lib/logger"
|
||||
"google.golang.org/api/iterator"
|
||||
"google.golang.org/api/option"
|
||||
@@ -97,6 +98,9 @@ func (fs *FS) ListParts() ([]common.Part, error) {
|
||||
if !strings.HasPrefix(file, dir) {
|
||||
return nil, fmt.Errorf("unexpected prefix for gcs key %q; want %q", file, dir)
|
||||
}
|
||||
if fscommon.IgnorePath(file) {
|
||||
continue
|
||||
}
|
||||
var p common.Part
|
||||
if !p.ParseFromRemotePath(file[len(dir):]) {
|
||||
logger.Infof("skipping unknown object %q", file)
|
||||
@@ -187,3 +191,56 @@ func (fs *FS) object(p common.Part) *storage.ObjectHandle {
|
||||
path := p.RemotePath(fs.Dir)
|
||||
return fs.bkt.Object(path)
|
||||
}
|
||||
|
||||
// DeleteFile deletes filePath at fs if it exists.
|
||||
//
|
||||
// The function does nothing if the filePath doesn't exists.
|
||||
func (fs *FS) DeleteFile(filePath string) error {
|
||||
path := fs.Dir + filePath
|
||||
o := fs.bkt.Object(path)
|
||||
ctx := context.Background()
|
||||
if err := o.Delete(ctx); err != nil {
|
||||
if err != storage.ErrObjectNotExist {
|
||||
return fmt.Errorf("cannot delete %q at %s (remote path %q): %s", filePath, fs, o.ObjectName(), err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// CreateFile creates filePath at fs and puts data into it.
|
||||
//
|
||||
// The file is overwritten if it exists.
|
||||
func (fs *FS) CreateFile(filePath string, data []byte) error {
|
||||
path := fs.Dir + filePath
|
||||
o := fs.bkt.Object(path)
|
||||
ctx := context.Background()
|
||||
w := o.NewWriter(ctx)
|
||||
n, err := w.Write(data)
|
||||
if err != nil {
|
||||
_ = w.Close()
|
||||
return fmt.Errorf("cannot upload %d bytes to %q at %s (remote path %q): %s", len(data), filePath, fs, o.ObjectName(), err)
|
||||
}
|
||||
if n != len(data) {
|
||||
_ = w.Close()
|
||||
return fmt.Errorf("wrong data size uploaded to %q at %s (remote path %q); got %d bytes; want %d bytes", filePath, fs, o.ObjectName(), n, len(data))
|
||||
}
|
||||
if err := w.Close(); err != nil {
|
||||
return fmt.Errorf("cannot close %q at %s (remote path %q): %s", filePath, fs, o.ObjectName(), err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// HasFile returns ture if filePath exists at fs.
|
||||
func (fs *FS) HasFile(filePath string) (bool, error) {
|
||||
path := fs.Dir + filePath
|
||||
o := fs.bkt.Object(path)
|
||||
ctx := context.Background()
|
||||
_, err := o.Attrs(ctx)
|
||||
if err != nil {
|
||||
if err == storage.ErrObjectNotExist {
|
||||
return false, nil
|
||||
}
|
||||
return false, fmt.Errorf("unexpected error when obtaining attributes for %q at %s (remote path %q): %s", filePath, fs, o.ObjectName(), err)
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
|
||||
@@ -1,14 +1,17 @@
|
||||
package s3remote
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"strings"
|
||||
|
||||
"github.com/VictoriaMetrics/VictoriaMetrics/lib/backup/common"
|
||||
"github.com/VictoriaMetrics/VictoriaMetrics/lib/backup/fscommon"
|
||||
"github.com/VictoriaMetrics/VictoriaMetrics/lib/logger"
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/awserr"
|
||||
"github.com/aws/aws-sdk-go/aws/session"
|
||||
"github.com/aws/aws-sdk-go/service/s3"
|
||||
"github.com/aws/aws-sdk-go/service/s3/s3manager"
|
||||
@@ -113,6 +116,9 @@ func (fs *FS) ListParts() ([]common.Part, error) {
|
||||
errOuter = fmt.Errorf("unexpected prefix for s3 key %q; want %q", file, dir)
|
||||
return false
|
||||
}
|
||||
if fscommon.IgnorePath(file) {
|
||||
continue
|
||||
}
|
||||
var p common.Part
|
||||
if !p.ParseFromRemotePath(file[len(dir):]) {
|
||||
logger.Infof("skipping unknown object %q", file)
|
||||
@@ -220,6 +226,78 @@ func (fs *FS) UploadPart(p common.Part, r io.Reader) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeleteFile deletes filePath from fs if it exists.
|
||||
//
|
||||
// The function does nothing if the file doesn't exist.
|
||||
func (fs *FS) DeleteFile(filePath string) error {
|
||||
// It looks like s3 may return `AccessDenied: Access Denied` instead of `s3.ErrCodeNoSuchKey`
|
||||
// on an attempt to delete non-existing file.
|
||||
// so just check whether the filePath exists before deleting it.
|
||||
// See https://github.com/VictoriaMetrics/VictoriaMetrics/issues/284 for details.
|
||||
ok, err := fs.HasFile(filePath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !ok {
|
||||
// Missing file - nothing to delete.
|
||||
return nil
|
||||
}
|
||||
|
||||
path := fs.Dir + filePath
|
||||
input := &s3.DeleteObjectInput{
|
||||
Bucket: aws.String(fs.Bucket),
|
||||
Key: aws.String(path),
|
||||
}
|
||||
if _, err := fs.s3.DeleteObject(input); err != nil {
|
||||
return fmt.Errorf("cannot delete %q at %s (remote path %q): %s", filePath, fs, path, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// CreateFile creates filePath at fs and puts data into it.
|
||||
//
|
||||
// The file is overwritten if it already exists.
|
||||
func (fs *FS) CreateFile(filePath string, data []byte) error {
|
||||
path := fs.Dir + filePath
|
||||
sr := &statReader{
|
||||
r: bytes.NewReader(data),
|
||||
}
|
||||
input := &s3manager.UploadInput{
|
||||
Bucket: aws.String(fs.Bucket),
|
||||
Key: aws.String(path),
|
||||
Body: sr,
|
||||
}
|
||||
_, err := fs.uploader.Upload(input)
|
||||
if err != nil {
|
||||
return fmt.Errorf("cannot upoad data to %q at %s (remote path %q): %s", filePath, fs, path, err)
|
||||
}
|
||||
l := int64(len(data))
|
||||
if sr.size != l {
|
||||
return fmt.Errorf("wrong data size uploaded to %q at %s; got %d bytes; want %d bytes", filePath, fs, sr.size, l)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// HasFile returns true if filePath exists at fs.
|
||||
func (fs *FS) HasFile(filePath string) (bool, error) {
|
||||
path := fs.Dir + filePath
|
||||
input := &s3.GetObjectInput{
|
||||
Bucket: aws.String(fs.Bucket),
|
||||
Key: aws.String(path),
|
||||
}
|
||||
o, err := fs.s3.GetObject(input)
|
||||
if err != nil {
|
||||
if ae, ok := err.(awserr.Error); ok && ae.Code() == s3.ErrCodeNoSuchKey {
|
||||
return false, nil
|
||||
}
|
||||
return false, fmt.Errorf("cannot open %q at %s (remote path %q): %s", filePath, fs, path, err)
|
||||
}
|
||||
if err := o.Body.Close(); err != nil {
|
||||
return false, fmt.Errorf("cannot close %q at %s (remote path %q): %s", filePath, fs, path, err)
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func (fs *FS) path(p common.Part) string {
|
||||
return p.RemotePath(fs.Dir)
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ import (
|
||||
"path/filepath"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"unsafe"
|
||||
"time"
|
||||
|
||||
"github.com/VictoriaMetrics/VictoriaMetrics/lib/filestream"
|
||||
"github.com/VictoriaMetrics/VictoriaMetrics/lib/fs"
|
||||
@@ -44,7 +44,7 @@ var (
|
||||
maxCachedInmemoryBlocksPerPartOnce sync.Once
|
||||
)
|
||||
|
||||
type partInternals struct {
|
||||
type part struct {
|
||||
ph partHeader
|
||||
|
||||
path string
|
||||
@@ -56,16 +56,9 @@ type partInternals struct {
|
||||
indexFile fs.ReadAtCloser
|
||||
itemsFile fs.ReadAtCloser
|
||||
lensFile fs.ReadAtCloser
|
||||
}
|
||||
|
||||
type part struct {
|
||||
partInternals
|
||||
|
||||
// Align atomic counters inside caches by 8 bytes on 32-bit architectures.
|
||||
// See https://github.com/VictoriaMetrics/VictoriaMetrics/issues/212 .
|
||||
_ [(8 - (unsafe.Sizeof(partInternals{}) % 8)) % 8]byte
|
||||
idxbCache indexBlockCache
|
||||
ibCache inmemoryBlockCache
|
||||
idxbCache *indexBlockCache
|
||||
ibCache *inmemoryBlockCache
|
||||
}
|
||||
|
||||
func openFilePart(path string) (*part, error) {
|
||||
@@ -132,8 +125,8 @@ func newPart(ph *partHeader, path string, size uint64, metaindexReader filestrea
|
||||
p.lensFile = lensFile
|
||||
|
||||
p.ph.CopyFrom(ph)
|
||||
p.idxbCache.Init()
|
||||
p.ibCache.Init()
|
||||
p.idxbCache = newIndexBlockCache()
|
||||
p.ibCache = newInmemoryBlockCache()
|
||||
|
||||
if len(errors) > 0 {
|
||||
// Return only the first error, since it has no sense in returning all errors.
|
||||
@@ -149,8 +142,8 @@ func (p *part) MustClose() {
|
||||
p.itemsFile.MustClose()
|
||||
p.lensFile.MustClose()
|
||||
|
||||
p.idxbCache.Reset()
|
||||
p.ibCache.Reset()
|
||||
p.idxbCache.MustClose()
|
||||
p.ibCache.MustClose()
|
||||
}
|
||||
|
||||
type indexBlock struct {
|
||||
@@ -179,27 +172,72 @@ type indexBlockCache struct {
|
||||
requests uint64
|
||||
misses uint64
|
||||
|
||||
m map[uint64]*indexBlock
|
||||
missesMap map[uint64]uint64
|
||||
mu sync.RWMutex
|
||||
m map[uint64]indexBlockCacheEntry
|
||||
mu sync.RWMutex
|
||||
|
||||
cleanerStopCh chan struct{}
|
||||
cleanerWG sync.WaitGroup
|
||||
}
|
||||
|
||||
func (idxbc *indexBlockCache) Init() {
|
||||
idxbc.m = make(map[uint64]*indexBlock)
|
||||
idxbc.missesMap = make(map[uint64]uint64)
|
||||
idxbc.requests = 0
|
||||
idxbc.misses = 0
|
||||
type indexBlockCacheEntry struct {
|
||||
// Atomically updated counters must go first in the struct, so they are properly
|
||||
// aligned to 8 bytes on 32-bit architectures.
|
||||
// See https://github.com/VictoriaMetrics/VictoriaMetrics/issues/212
|
||||
lastAccessTime uint64
|
||||
|
||||
idxb *indexBlock
|
||||
}
|
||||
|
||||
func (idxbc *indexBlockCache) Reset() {
|
||||
func newIndexBlockCache() *indexBlockCache {
|
||||
var idxbc indexBlockCache
|
||||
idxbc.m = make(map[uint64]indexBlockCacheEntry)
|
||||
idxbc.cleanerStopCh = make(chan struct{})
|
||||
idxbc.cleanerWG.Add(1)
|
||||
go func() {
|
||||
defer idxbc.cleanerWG.Done()
|
||||
idxbc.cleaner()
|
||||
}()
|
||||
return &idxbc
|
||||
}
|
||||
|
||||
func (idxbc *indexBlockCache) MustClose() {
|
||||
close(idxbc.cleanerStopCh)
|
||||
idxbc.cleanerWG.Wait()
|
||||
|
||||
atomic.AddUint64(&indexBlockCacheRequests, idxbc.requests)
|
||||
atomic.AddUint64(&indexBlockCacheMisses, idxbc.misses)
|
||||
// It is safe returning idxbc.m to pool, since the Reset must be called
|
||||
// when the idxbc entries are no longer accessed by concurrent goroutines.
|
||||
for _, idxb := range idxbc.m {
|
||||
putIndexBlock(idxb)
|
||||
for _, idxbe := range idxbc.m {
|
||||
putIndexBlock(idxbe.idxb)
|
||||
}
|
||||
idxbc.Init()
|
||||
idxbc.m = nil
|
||||
}
|
||||
|
||||
// cleaner periodically cleans least recently used items.
|
||||
func (idxbc *indexBlockCache) cleaner() {
|
||||
t := time.NewTimer(5 * time.Second)
|
||||
for {
|
||||
select {
|
||||
case <-t.C:
|
||||
idxbc.cleanByTimeout()
|
||||
case <-idxbc.cleanerStopCh:
|
||||
t.Stop()
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (idxbc *indexBlockCache) cleanByTimeout() {
|
||||
currentTime := atomic.LoadUint64(¤tTimestamp)
|
||||
idxbc.mu.Lock()
|
||||
for k, idxbe := range idxbc.m {
|
||||
// Delete items accessed more than 10 minutes ago.
|
||||
if currentTime-atomic.LoadUint64(&idxbe.lastAccessTime) > 10*60 {
|
||||
delete(idxbc.m, k)
|
||||
}
|
||||
}
|
||||
idxbc.mu.Unlock()
|
||||
}
|
||||
|
||||
var (
|
||||
@@ -210,16 +248,17 @@ var (
|
||||
func (idxbc *indexBlockCache) Get(k uint64) *indexBlock {
|
||||
atomic.AddUint64(&idxbc.requests, 1)
|
||||
idxbc.mu.RLock()
|
||||
idxb := idxbc.m[k]
|
||||
idxbe, ok := idxbc.m[k]
|
||||
idxbc.mu.RUnlock()
|
||||
|
||||
if idxb != nil {
|
||||
return idxb
|
||||
if ok {
|
||||
currentTime := atomic.LoadUint64(¤tTimestamp)
|
||||
if atomic.LoadUint64(&idxbe.lastAccessTime) != currentTime {
|
||||
atomic.StoreUint64(&idxbe.lastAccessTime, currentTime)
|
||||
}
|
||||
return idxbe.idxb
|
||||
}
|
||||
atomic.AddUint64(&idxbc.misses, 1)
|
||||
idxbc.mu.Lock()
|
||||
idxbc.missesMap[k]++
|
||||
idxbc.mu.Unlock()
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -229,13 +268,6 @@ func (idxbc *indexBlockCache) Get(k uint64) *indexBlock {
|
||||
func (idxbc *indexBlockCache) Put(k uint64, idxb *indexBlock) bool {
|
||||
idxbc.mu.Lock()
|
||||
|
||||
if idxbc.missesMap[k] < 2 {
|
||||
// Do not pollute cache with infrequently accessed items, since they may
|
||||
// evict frequently accessed items.
|
||||
idxbc.mu.Unlock()
|
||||
return false
|
||||
}
|
||||
|
||||
// Remove superflouos entries.
|
||||
if overflow := len(idxbc.m) - getMaxCachedIndexBlocksPerPart(); overflow > 0 {
|
||||
// Remove 10% of items from the cache.
|
||||
@@ -250,21 +282,13 @@ func (idxbc *indexBlockCache) Put(k uint64, idxb *indexBlock) bool {
|
||||
}
|
||||
}
|
||||
}
|
||||
if overflow := len(idxbc.missesMap) - 8*getMaxCachedIndexBlocksPerPart(); overflow > 0 {
|
||||
// Remove 10% of items from the cache.
|
||||
overflow = int(float64(len(idxbc.missesMap)) * 0.1)
|
||||
for k := range idxbc.missesMap {
|
||||
delete(idxbc.missesMap, k)
|
||||
overflow--
|
||||
if overflow == 0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Store the frequently accessed idxb in the cache.
|
||||
delete(idxbc.missesMap, k)
|
||||
idxbc.m[k] = idxb
|
||||
// Store idxb in the cache.
|
||||
idxbe := indexBlockCacheEntry{
|
||||
lastAccessTime: atomic.LoadUint64(¤tTimestamp),
|
||||
idxb: idxb,
|
||||
}
|
||||
idxbc.m[k] = idxbe
|
||||
idxbc.mu.Unlock()
|
||||
return true
|
||||
}
|
||||
@@ -291,9 +315,11 @@ type inmemoryBlockCache struct {
|
||||
requests uint64
|
||||
misses uint64
|
||||
|
||||
m map[inmemoryBlockCacheKey]*inmemoryBlock
|
||||
missesMap map[inmemoryBlockCacheKey]uint64
|
||||
mu sync.RWMutex
|
||||
m map[inmemoryBlockCacheKey]inmemoryBlockCacheEntry
|
||||
mu sync.RWMutex
|
||||
|
||||
cleanerStopCh chan struct{}
|
||||
cleanerWG sync.WaitGroup
|
||||
}
|
||||
|
||||
type inmemoryBlockCacheKey struct {
|
||||
@@ -309,22 +335,66 @@ func (ibck *inmemoryBlockCacheKey) Init(bh *blockHeader) {
|
||||
ibck.itemsBlockOffset = bh.itemsBlockOffset
|
||||
}
|
||||
|
||||
func (ibc *inmemoryBlockCache) Init() {
|
||||
ibc.m = make(map[inmemoryBlockCacheKey]*inmemoryBlock)
|
||||
ibc.missesMap = make(map[inmemoryBlockCacheKey]uint64)
|
||||
ibc.requests = 0
|
||||
ibc.misses = 0
|
||||
type inmemoryBlockCacheEntry struct {
|
||||
// Atomically updated counters must go first in the struct, so they are properly
|
||||
// aligned to 8 bytes on 32-bit architectures.
|
||||
// See https://github.com/VictoriaMetrics/VictoriaMetrics/issues/212
|
||||
lastAccessTime uint64
|
||||
|
||||
ib *inmemoryBlock
|
||||
}
|
||||
|
||||
func (ibc *inmemoryBlockCache) Reset() {
|
||||
func newInmemoryBlockCache() *inmemoryBlockCache {
|
||||
var ibc inmemoryBlockCache
|
||||
ibc.m = make(map[inmemoryBlockCacheKey]inmemoryBlockCacheEntry)
|
||||
|
||||
ibc.cleanerStopCh = make(chan struct{})
|
||||
ibc.cleanerWG.Add(1)
|
||||
go func() {
|
||||
defer ibc.cleanerWG.Done()
|
||||
ibc.cleaner()
|
||||
}()
|
||||
return &ibc
|
||||
}
|
||||
|
||||
func (ibc *inmemoryBlockCache) MustClose() {
|
||||
close(ibc.cleanerStopCh)
|
||||
ibc.cleanerWG.Wait()
|
||||
|
||||
atomic.AddUint64(&inmemoryBlockCacheRequests, ibc.requests)
|
||||
atomic.AddUint64(&inmemoryBlockCacheMisses, ibc.misses)
|
||||
// It is safe returning ibc.m entries to pool, since the Reset function may be called
|
||||
// only if no other goroutines access ibc entries.
|
||||
for _, ib := range ibc.m {
|
||||
putInmemoryBlock(ib)
|
||||
for _, ibe := range ibc.m {
|
||||
putInmemoryBlock(ibe.ib)
|
||||
}
|
||||
ibc.Init()
|
||||
ibc.m = nil
|
||||
}
|
||||
|
||||
// cleaner periodically cleans least recently used items.
|
||||
func (ibc *inmemoryBlockCache) cleaner() {
|
||||
t := time.NewTimer(5 * time.Second)
|
||||
for {
|
||||
select {
|
||||
case <-t.C:
|
||||
ibc.cleanByTimeout()
|
||||
case <-ibc.cleanerStopCh:
|
||||
t.Stop()
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (ibc *inmemoryBlockCache) cleanByTimeout() {
|
||||
currentTime := atomic.LoadUint64(¤tTimestamp)
|
||||
ibc.mu.Lock()
|
||||
for k, ibe := range ibc.m {
|
||||
// Delete items accessed more than 10 minutes ago.
|
||||
if currentTime-atomic.LoadUint64(&ibe.lastAccessTime) > 10*60 {
|
||||
delete(ibc.m, k)
|
||||
}
|
||||
}
|
||||
ibc.mu.Unlock()
|
||||
}
|
||||
|
||||
var (
|
||||
@@ -336,16 +406,17 @@ func (ibc *inmemoryBlockCache) Get(k inmemoryBlockCacheKey) *inmemoryBlock {
|
||||
atomic.AddUint64(&ibc.requests, 1)
|
||||
|
||||
ibc.mu.RLock()
|
||||
ib := ibc.m[k]
|
||||
ibe, ok := ibc.m[k]
|
||||
ibc.mu.RUnlock()
|
||||
|
||||
if ib != nil {
|
||||
return ib
|
||||
if ok {
|
||||
currentTime := atomic.LoadUint64(¤tTimestamp)
|
||||
if atomic.LoadUint64(&ibe.lastAccessTime) != currentTime {
|
||||
atomic.StoreUint64(&ibe.lastAccessTime, currentTime)
|
||||
}
|
||||
return ibe.ib
|
||||
}
|
||||
atomic.AddUint64(&ibc.misses, 1)
|
||||
ibc.mu.Lock()
|
||||
ibc.missesMap[k]++
|
||||
ibc.mu.Unlock()
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -355,14 +426,7 @@ func (ibc *inmemoryBlockCache) Get(k inmemoryBlockCacheKey) *inmemoryBlock {
|
||||
func (ibc *inmemoryBlockCache) Put(k inmemoryBlockCacheKey, ib *inmemoryBlock) bool {
|
||||
ibc.mu.Lock()
|
||||
|
||||
if ibc.missesMap[k] < 2 {
|
||||
// Do not cache entry with low number of accesses, since it may evict
|
||||
// frequently accessed entries from the cache.
|
||||
ibc.mu.Unlock()
|
||||
return false
|
||||
}
|
||||
|
||||
// Clean superflouos entries in ibc.m and ibc.missesMap.
|
||||
// Clean superflouos entries in cache.
|
||||
if overflow := len(ibc.m) - getMaxCachedInmemoryBlocksPerPart(); overflow > 0 {
|
||||
// Remove 10% of items from the cache.
|
||||
overflow = int(float64(len(ibc.m)) * 0.1)
|
||||
@@ -376,21 +440,13 @@ func (ibc *inmemoryBlockCache) Put(k inmemoryBlockCacheKey, ib *inmemoryBlock) b
|
||||
}
|
||||
}
|
||||
}
|
||||
if overflow := len(ibc.missesMap) - 8*getMaxCachedInmemoryBlocksPerPart(); overflow > 0 {
|
||||
// Remove 10% of items from the cache.
|
||||
overflow = int(float64(len(ibc.missesMap)) * 0.1)
|
||||
for k := range ibc.missesMap {
|
||||
delete(ibc.missesMap, k)
|
||||
overflow--
|
||||
if overflow == 0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// The entry is frequently accessed, so store it in the cache.
|
||||
delete(ibc.missesMap, k)
|
||||
ibc.m[k] = ib
|
||||
// Store ib in the cache.
|
||||
ibe := inmemoryBlockCacheEntry{
|
||||
lastAccessTime: atomic.LoadUint64(¤tTimestamp),
|
||||
ib: ib,
|
||||
}
|
||||
ibc.m[k] = ibe
|
||||
ibc.mu.Unlock()
|
||||
return true
|
||||
}
|
||||
@@ -409,3 +465,15 @@ func (ibc *inmemoryBlockCache) Requests() uint64 {
|
||||
func (ibc *inmemoryBlockCache) Misses() uint64 {
|
||||
return atomic.LoadUint64(&ibc.misses)
|
||||
}
|
||||
|
||||
func init() {
|
||||
go func() {
|
||||
t := time.NewTimer(time.Second)
|
||||
for tm := range t.C {
|
||||
t := uint64(tm.Unix())
|
||||
atomic.StoreUint64(¤tTimestamp, t)
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
var currentTimestamp uint64
|
||||
|
||||
@@ -82,8 +82,8 @@ func (ps *partSearch) Init(p *part, shouldCacheBlock func(item []byte) bool) {
|
||||
ps.reset()
|
||||
|
||||
ps.p = p
|
||||
ps.idxbCache = &p.idxbCache
|
||||
ps.ibCache = &p.ibCache
|
||||
ps.idxbCache = p.idxbCache
|
||||
ps.ibCache = p.ibCache
|
||||
}
|
||||
|
||||
// Seek seeks for the first item greater or equal to k in ps.
|
||||
|
||||
@@ -29,28 +29,33 @@ var rollupFuncs = map[string]bool{
|
||||
"absent_over_time": true,
|
||||
|
||||
// Additional rollup funcs.
|
||||
"default_rollup": true,
|
||||
"sum2_over_time": true,
|
||||
"geomean_over_time": true,
|
||||
"first_over_time": true,
|
||||
"last_over_time": true,
|
||||
"distinct_over_time": true,
|
||||
"increases_over_time": true,
|
||||
"decreases_over_time": true,
|
||||
"integrate": true,
|
||||
"ideriv": true,
|
||||
"lifetime": true,
|
||||
"lag": true,
|
||||
"scrape_interval": true,
|
||||
"share_le_over_time": true,
|
||||
"share_gt_over_time": true,
|
||||
"histogram_over_time": true,
|
||||
"rollup": true,
|
||||
"rollup_rate": true,
|
||||
"rollup_deriv": true,
|
||||
"rollup_delta": true,
|
||||
"rollup_increase": true,
|
||||
"rollup_candlestick": true,
|
||||
"default_rollup": true,
|
||||
"sum2_over_time": true,
|
||||
"geomean_over_time": true,
|
||||
"first_over_time": true,
|
||||
"last_over_time": true,
|
||||
"distinct_over_time": true,
|
||||
"increases_over_time": true,
|
||||
"decreases_over_time": true,
|
||||
"integrate": true,
|
||||
"ideriv": true,
|
||||
"lifetime": true,
|
||||
"lag": true,
|
||||
"scrape_interval": true,
|
||||
"tmin_over_time": true,
|
||||
"tmax_over_time": true,
|
||||
"share_le_over_time": true,
|
||||
"share_gt_over_time": true,
|
||||
"histogram_over_time": true,
|
||||
"rollup": true,
|
||||
"rollup_rate": true,
|
||||
"rollup_deriv": true,
|
||||
"rollup_delta": true,
|
||||
"rollup_increase": true,
|
||||
"rollup_candlestick": true,
|
||||
"aggr_over_time": true,
|
||||
"hoeffding_bound_upper": true,
|
||||
"hoeffding_bound_lower": true,
|
||||
}
|
||||
|
||||
// IsRollupFunc returns whether funcName is known rollup function.
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package prompb
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
@@ -8,18 +9,20 @@ import (
|
||||
"github.com/golang/snappy"
|
||||
)
|
||||
|
||||
var maxInsertRequestSize = flag.Int("maxInsertRequestSize", 32*1024*1024, "The maximum size in bytes of a single Prometheus remote_write API request")
|
||||
|
||||
// ReadSnappy reads r, unpacks it using snappy, appends it to dst
|
||||
// and returns the result.
|
||||
func ReadSnappy(dst []byte, r io.Reader, maxSize int64) ([]byte, error) {
|
||||
lr := io.LimitReader(r, maxSize+1)
|
||||
func ReadSnappy(dst []byte, r io.Reader) ([]byte, error) {
|
||||
lr := io.LimitReader(r, int64(*maxInsertRequestSize)+1)
|
||||
bb := bodyBufferPool.Get()
|
||||
reqLen, err := bb.ReadFrom(lr)
|
||||
if err != nil {
|
||||
bodyBufferPool.Put(bb)
|
||||
return dst, fmt.Errorf("cannot read compressed request: %s", err)
|
||||
}
|
||||
if reqLen > maxSize {
|
||||
return dst, fmt.Errorf("too big packed request; mustn't exceed %d bytes", maxSize)
|
||||
if reqLen > int64(*maxInsertRequestSize) {
|
||||
return dst, fmt.Errorf("too big packed request; mustn't exceed `-maxInsertRequestSize=%d` bytes", *maxInsertRequestSize)
|
||||
}
|
||||
|
||||
buf := dst[len(dst):cap(dst)]
|
||||
@@ -29,8 +32,8 @@ func ReadSnappy(dst []byte, r io.Reader, maxSize int64) ([]byte, error) {
|
||||
err = fmt.Errorf("cannot decompress request with length %d: %s", reqLen, err)
|
||||
return dst, err
|
||||
}
|
||||
if int64(len(buf)) > maxSize {
|
||||
return dst, fmt.Errorf("too big unpacked request; musn't exceed %d bytes", maxSize)
|
||||
if len(buf) > *maxInsertRequestSize {
|
||||
return dst, fmt.Errorf("too big unpacked request; mustn't exceed `-maxInsertRequestSize=%d` bytes", *maxInsertRequestSize)
|
||||
}
|
||||
if len(buf) > 0 && len(dst) < cap(dst) && &buf[0] == &dst[len(dst):cap(dst)][0] {
|
||||
dst = dst[:len(dst)+len(buf)]
|
||||
|
||||
@@ -5,7 +5,7 @@ import (
|
||||
"path/filepath"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"unsafe"
|
||||
"time"
|
||||
|
||||
"github.com/VictoriaMetrics/VictoriaMetrics/lib/filestream"
|
||||
"github.com/VictoriaMetrics/VictoriaMetrics/lib/fs"
|
||||
@@ -28,7 +28,8 @@ var (
|
||||
maxCachedIndexBlocksPerPartOnce sync.Once
|
||||
)
|
||||
|
||||
type partInternals struct {
|
||||
// part represents a searchable part containing time series data.
|
||||
type part struct {
|
||||
ph partHeader
|
||||
|
||||
// Filesystem path to the part.
|
||||
@@ -44,16 +45,8 @@ type partInternals struct {
|
||||
indexFile fs.ReadAtCloser
|
||||
|
||||
metaindex []metaindexRow
|
||||
}
|
||||
|
||||
// part represents a searchable part containing time series data.
|
||||
type part struct {
|
||||
partInternals
|
||||
|
||||
// Align ibCache to 8 bytes in order to align internal counters on 32-bit architectures.
|
||||
// See https://github.com/VictoriaMetrics/VictoriaMetrics/issues/212
|
||||
_ [(8 - (unsafe.Sizeof(partInternals{}) % 8)) % 8]byte
|
||||
ibCache indexBlockCache
|
||||
ibCache *indexBlockCache
|
||||
}
|
||||
|
||||
// openFilePart opens file-based part from the given path.
|
||||
@@ -132,7 +125,7 @@ func newPart(ph *partHeader, path string, size uint64, metaindexReader filestrea
|
||||
return nil, err
|
||||
}
|
||||
|
||||
p.ibCache.Init()
|
||||
p.ibCache = newIndexBlockCache()
|
||||
|
||||
return &p, nil
|
||||
}
|
||||
@@ -152,7 +145,7 @@ func (p *part) MustClose() {
|
||||
p.indexFile.MustClose()
|
||||
|
||||
isBig := p.ph.RowsCount > maxRowsPerSmallPart()
|
||||
p.ibCache.Reset(isBig)
|
||||
p.ibCache.MustClose(isBig)
|
||||
}
|
||||
|
||||
type indexBlock struct {
|
||||
@@ -180,19 +173,41 @@ type indexBlockCache struct {
|
||||
requests uint64
|
||||
misses uint64
|
||||
|
||||
m map[uint64]*indexBlock
|
||||
m map[uint64]indexBlockCacheEntry
|
||||
missesMap map[uint64]uint64
|
||||
mu sync.RWMutex
|
||||
|
||||
cleanerStopCh chan struct{}
|
||||
cleanerWG sync.WaitGroup
|
||||
}
|
||||
|
||||
func (ibc *indexBlockCache) Init() {
|
||||
ibc.m = make(map[uint64]*indexBlock)
|
||||
type indexBlockCacheEntry struct {
|
||||
// Atomically updated counters must go first in the struct, so they are properly
|
||||
// aligned to 8 bytes on 32-bit architectures.
|
||||
// See https://github.com/VictoriaMetrics/VictoriaMetrics/issues/212
|
||||
lastAccessTime uint64
|
||||
|
||||
ib *indexBlock
|
||||
}
|
||||
|
||||
func newIndexBlockCache() *indexBlockCache {
|
||||
var ibc indexBlockCache
|
||||
ibc.m = make(map[uint64]indexBlockCacheEntry)
|
||||
ibc.missesMap = make(map[uint64]uint64)
|
||||
ibc.requests = 0
|
||||
ibc.misses = 0
|
||||
|
||||
ibc.cleanerStopCh = make(chan struct{})
|
||||
ibc.cleanerWG.Add(1)
|
||||
go func() {
|
||||
defer ibc.cleanerWG.Done()
|
||||
ibc.cleaner()
|
||||
}()
|
||||
return &ibc
|
||||
}
|
||||
|
||||
func (ibc *indexBlockCache) Reset(isBig bool) {
|
||||
func (ibc *indexBlockCache) MustClose(isBig bool) {
|
||||
close(ibc.cleanerStopCh)
|
||||
ibc.cleanerWG.Wait()
|
||||
|
||||
if isBig {
|
||||
atomic.AddUint64(&bigIndexBlockCacheRequests, ibc.requests)
|
||||
atomic.AddUint64(&bigIndexBlockCacheMisses, ibc.misses)
|
||||
@@ -202,10 +217,36 @@ func (ibc *indexBlockCache) Reset(isBig bool) {
|
||||
}
|
||||
// It is safe returning ibc.m itemst to the pool, since Reset must
|
||||
// be called only when no other goroutines access ibc entries.
|
||||
for _, ib := range ibc.m {
|
||||
putIndexBlock(ib)
|
||||
for _, ibe := range ibc.m {
|
||||
putIndexBlock(ibe.ib)
|
||||
}
|
||||
ibc.Init()
|
||||
ibc.m = nil
|
||||
}
|
||||
|
||||
// cleaner periodically cleans least recently used items.
|
||||
func (ibc *indexBlockCache) cleaner() {
|
||||
t := time.NewTimer(5 * time.Second)
|
||||
for {
|
||||
select {
|
||||
case <-t.C:
|
||||
ibc.cleanByTimeout()
|
||||
case <-ibc.cleanerStopCh:
|
||||
t.Stop()
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (ibc *indexBlockCache) cleanByTimeout() {
|
||||
currentTime := atomic.LoadUint64(¤tTimestamp)
|
||||
ibc.mu.Lock()
|
||||
for k, ibe := range ibc.m {
|
||||
// Delete items accessed more than 10 minutes ago.
|
||||
if currentTime-atomic.LoadUint64(&ibe.lastAccessTime) > 10*60 {
|
||||
delete(ibc.m, k)
|
||||
}
|
||||
}
|
||||
ibc.mu.Unlock()
|
||||
}
|
||||
|
||||
var (
|
||||
@@ -220,11 +261,15 @@ func (ibc *indexBlockCache) Get(k uint64) *indexBlock {
|
||||
atomic.AddUint64(&ibc.requests, 1)
|
||||
|
||||
ibc.mu.RLock()
|
||||
ib := ibc.m[k]
|
||||
ibe, ok := ibc.m[k]
|
||||
ibc.mu.RUnlock()
|
||||
|
||||
if ib != nil {
|
||||
return ib
|
||||
if ok {
|
||||
currentTime := atomic.LoadUint64(¤tTimestamp)
|
||||
if atomic.LoadUint64(&ibe.lastAccessTime) != currentTime {
|
||||
atomic.StoreUint64(&ibe.lastAccessTime, currentTime)
|
||||
}
|
||||
return ibe.ib
|
||||
}
|
||||
atomic.AddUint64(&ibc.misses, 1)
|
||||
ibc.mu.Lock()
|
||||
@@ -270,7 +315,11 @@ func (ibc *indexBlockCache) Put(k uint64, ib *indexBlock) bool {
|
||||
|
||||
// Store frequently requested ib in the cache.
|
||||
delete(ibc.missesMap, k)
|
||||
ibc.m[k] = ib
|
||||
ibe := indexBlockCacheEntry{
|
||||
lastAccessTime: atomic.LoadUint64(¤tTimestamp),
|
||||
ib: ib,
|
||||
}
|
||||
ibc.m[k] = ibe
|
||||
ibc.mu.Unlock()
|
||||
return true
|
||||
}
|
||||
@@ -289,3 +338,15 @@ func (ibc *indexBlockCache) Len() uint64 {
|
||||
ibc.mu.Unlock()
|
||||
return n
|
||||
}
|
||||
|
||||
func init() {
|
||||
go func() {
|
||||
t := time.NewTimer(time.Second)
|
||||
for tm := range t.C {
|
||||
t := uint64(tm.Unix())
|
||||
atomic.StoreUint64(¤tTimestamp, t)
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
var currentTimestamp uint64
|
||||
|
||||
@@ -88,7 +88,7 @@ func (ps *partSearch) Init(p *part, tsids []TSID, tr TimeRange, fetchData bool)
|
||||
ps.tr = tr
|
||||
ps.fetchData = fetchData
|
||||
ps.metaindex = p.metaindex
|
||||
ps.ibCache = &p.ibCache
|
||||
ps.ibCache = p.ibCache
|
||||
|
||||
// Advance to the first tsid. There is no need in checking
|
||||
// the returned result, since it will be checked in NextBlock.
|
||||
|
||||
@@ -76,7 +76,7 @@ func getMaxRawRowsPerPartition() int {
|
||||
if n > 500e3 {
|
||||
n = 500e3
|
||||
}
|
||||
maxRawRowsPerPartition = n / rawRowsShardsPerPartition
|
||||
maxRawRowsPerPartition = n
|
||||
})
|
||||
return maxRawRowsPerPartition
|
||||
}
|
||||
|
||||
@@ -110,10 +110,8 @@ func testAppendPartsToMerge(t *testing.T, maxPartsToMerge int, initialRowsCount,
|
||||
prefix := []*partWrapper{
|
||||
{
|
||||
p: &part{
|
||||
partInternals: partInternals{
|
||||
ph: partHeader{
|
||||
RowsCount: 1234,
|
||||
},
|
||||
ph: partHeader{
|
||||
RowsCount: 1234,
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -146,10 +144,8 @@ func newTestPartWrappersForRowsCount(rowsCount []uint64) []*partWrapper {
|
||||
for _, rc := range rowsCount {
|
||||
pw := &partWrapper{
|
||||
p: &part{
|
||||
partInternals: partInternals{
|
||||
ph: partHeader{
|
||||
RowsCount: rc,
|
||||
},
|
||||
ph: partHeader{
|
||||
RowsCount: rc,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -553,9 +553,12 @@ func (s *Storage) mustSaveHourMetricIDs(hm *hourMetricIDs, name string) {
|
||||
|
||||
// Marshal hm.m
|
||||
dst = encoding.MarshalUint64(dst, uint64(hm.m.Len()))
|
||||
for _, metricID := range hm.m.AppendTo(nil) {
|
||||
dst = encoding.MarshalUint64(dst, metricID)
|
||||
}
|
||||
hm.m.ForEach(func(part []uint64) bool {
|
||||
for _, metricID := range part {
|
||||
dst = encoding.MarshalUint64(dst, metricID)
|
||||
}
|
||||
return true
|
||||
})
|
||||
|
||||
if err := ioutil.WriteFile(path, dst, 0644); err != nil {
|
||||
logger.Panicf("FATAL: cannot write %d bytes to %q: %s", len(dst), path, err)
|
||||
|
||||
@@ -245,10 +245,12 @@ func TestUpdateCurrHourMetricIDs(t *testing.T) {
|
||||
return
|
||||
}
|
||||
m := pendingHourEntries.Clone()
|
||||
origMetricIDs := hmOrig.m.AppendTo(nil)
|
||||
for _, metricID := range origMetricIDs {
|
||||
m.Add(metricID)
|
||||
}
|
||||
hmOrig.m.ForEach(func(part []uint64) bool {
|
||||
for _, metricID := range part {
|
||||
m.Add(metricID)
|
||||
}
|
||||
return true
|
||||
})
|
||||
if !hmCurr.m.Equal(m) {
|
||||
t.Fatalf("unexpected hm.m; got %v; want %v", hmCurr.m, m)
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package uint64set
|
||||
import (
|
||||
"math/bits"
|
||||
"sort"
|
||||
"sync"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
@@ -31,21 +32,26 @@ func (s *bucket32Sorter) Swap(i, j int) {
|
||||
|
||||
// Clone returns an independent copy of s.
|
||||
func (s *Set) Clone() *Set {
|
||||
if s == nil {
|
||||
if s == nil || s.itemsCount == 0 {
|
||||
// Return an empty set, so data could be added into it later.
|
||||
return &Set{}
|
||||
}
|
||||
var dst Set
|
||||
dst.itemsCount = s.itemsCount
|
||||
if len(s.buckets) > 0 {
|
||||
dst.buckets = make([]bucket32, len(s.buckets))
|
||||
for i := range s.buckets {
|
||||
s.buckets[i].copyTo(&dst.buckets[i])
|
||||
}
|
||||
dst.buckets = make([]bucket32, len(s.buckets))
|
||||
for i := range s.buckets {
|
||||
s.buckets[i].copyTo(&dst.buckets[i])
|
||||
}
|
||||
return &dst
|
||||
}
|
||||
|
||||
func (s *Set) cloneShallow() *Set {
|
||||
var dst Set
|
||||
dst.itemsCount = s.itemsCount
|
||||
dst.buckets = append(dst.buckets[:0], s.buckets...)
|
||||
return &dst
|
||||
}
|
||||
|
||||
// SizeBytes returns an estimate size of s in RAM.
|
||||
func (s *Set) SizeBytes() uint64 {
|
||||
if s == nil {
|
||||
@@ -143,57 +149,93 @@ func (s *Set) AppendTo(dst []uint64) []uint64 {
|
||||
dst = append(dst[:cap(dst)], make([]uint64, n)...)
|
||||
dst = dst[:dstLen]
|
||||
}
|
||||
// sort s.buckets if it isn't sorted yet
|
||||
if !sort.IsSorted(&s.buckets) {
|
||||
sort.Sort(&s.buckets)
|
||||
}
|
||||
s.sort()
|
||||
for i := range s.buckets {
|
||||
dst = s.buckets[i].appendTo(dst)
|
||||
}
|
||||
return dst
|
||||
}
|
||||
|
||||
func (s *Set) sort() {
|
||||
// sort s.buckets if it isn't sorted yet
|
||||
if !sort.IsSorted(&s.buckets) {
|
||||
sort.Sort(&s.buckets)
|
||||
}
|
||||
}
|
||||
|
||||
// Union adds all the items from a to s.
|
||||
func (s *Set) Union(a *Set) {
|
||||
// Clone a, since AppendTo may mutate it below.
|
||||
aCopy := a.Clone()
|
||||
if s.Len() == 0 {
|
||||
// Fast path if the initial set is empty.
|
||||
// Fast path - just copy a.
|
||||
aCopy := a.Clone()
|
||||
*s = *aCopy
|
||||
return
|
||||
}
|
||||
// TODO: optimize it
|
||||
for _, x := range aCopy.AppendTo(nil) {
|
||||
s.Add(x)
|
||||
if a.Len() == 0 {
|
||||
// Fast path - nothing to union.
|
||||
return
|
||||
}
|
||||
a.ForEach(func(part []uint64) bool {
|
||||
for _, x := range part {
|
||||
s.Add(x)
|
||||
}
|
||||
return true
|
||||
})
|
||||
}
|
||||
|
||||
// Intersect removes all the items missing in a from s.
|
||||
func (s *Set) Intersect(a *Set) {
|
||||
if a.Len() == 0 {
|
||||
// Fast path
|
||||
if s.Len() == 0 || a.Len() == 0 {
|
||||
// Fast path - the result is empty.
|
||||
*s = Set{}
|
||||
return
|
||||
}
|
||||
// TODO: optimize it
|
||||
for _, x := range s.AppendTo(nil) {
|
||||
if !a.Has(x) {
|
||||
s.Del(x)
|
||||
// Make shallow copy of `a`, since it can be modified below.
|
||||
a = a.cloneShallow()
|
||||
a.sort()
|
||||
s.sort()
|
||||
itemsCount := 0
|
||||
i := 0
|
||||
j := 0
|
||||
for {
|
||||
for i < len(s.buckets) && j <= len(a.buckets) && s.buckets[i].hi < a.buckets[j].hi {
|
||||
s.buckets[i] = bucket32{}
|
||||
i++
|
||||
}
|
||||
if i >= len(s.buckets) {
|
||||
break
|
||||
}
|
||||
for j < len(a.buckets) && a.buckets[j].hi < s.buckets[i].hi {
|
||||
j++
|
||||
}
|
||||
if j >= len(a.buckets) {
|
||||
for i < len(s.buckets) {
|
||||
s.buckets[i] = bucket32{}
|
||||
i++
|
||||
}
|
||||
break
|
||||
}
|
||||
if s.buckets[i].hi == a.buckets[j].hi {
|
||||
itemsCount += s.buckets[i].intersect(&a.buckets[j])
|
||||
i++
|
||||
j++
|
||||
}
|
||||
}
|
||||
s.itemsCount = itemsCount
|
||||
}
|
||||
|
||||
// Subtract removes from s all the shared items between s and a.
|
||||
func (s *Set) Subtract(a *Set) {
|
||||
if s.Len() == 0 {
|
||||
if s.Len() == 0 || a.Len() == 0 {
|
||||
// Fast path - nothing to subtract.
|
||||
return
|
||||
}
|
||||
// Copy a because AppendTo below can mutate a.
|
||||
aCopy := a.Clone()
|
||||
// TODO: optimize it
|
||||
for _, x := range aCopy.AppendTo(nil) {
|
||||
s.Del(x)
|
||||
}
|
||||
a.ForEach(func(part []uint64) bool {
|
||||
for _, x := range part {
|
||||
s.Del(x)
|
||||
}
|
||||
return true
|
||||
})
|
||||
}
|
||||
|
||||
// Equal returns true if s contains the same items as a.
|
||||
@@ -201,21 +243,107 @@ func (s *Set) Equal(a *Set) bool {
|
||||
if s.Len() != a.Len() {
|
||||
return false
|
||||
}
|
||||
// Copy a because AppendTo below can mutate a
|
||||
aCopy := a.Clone()
|
||||
// TODO: optimize it
|
||||
for _, x := range aCopy.AppendTo(nil) {
|
||||
if !s.Has(x) {
|
||||
return false
|
||||
equal := true
|
||||
a.ForEach(func(part []uint64) bool {
|
||||
for _, x := range part {
|
||||
if !s.Has(x) {
|
||||
equal = false
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
})
|
||||
return equal
|
||||
}
|
||||
|
||||
// ForEach calls f for all the items stored in s.
|
||||
//
|
||||
// Each call to f contains part with arbitrary part of items stored in the set.
|
||||
// The iteration is stopped if f returns false.
|
||||
func (s *Set) ForEach(f func(part []uint64) bool) {
|
||||
if s == nil {
|
||||
return
|
||||
}
|
||||
for i := range s.buckets {
|
||||
if !s.buckets[i].forEach(f) {
|
||||
return
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
type bucket32 struct {
|
||||
hi uint32
|
||||
b16his []uint16
|
||||
buckets []bucket16
|
||||
|
||||
// hint may contain bucket index for the last successful add or del operation.
|
||||
// This allows saving CPU time on subsequent calls to the same bucket.
|
||||
hint int
|
||||
}
|
||||
|
||||
func (b *bucket32) cloneShallow() *bucket32 {
|
||||
var dst bucket32
|
||||
dst.hi = b.hi
|
||||
dst.b16his = append(dst.b16his[:0], b.b16his...)
|
||||
dst.buckets = append(dst.buckets[:0], b.buckets...)
|
||||
dst.hint = b.hint
|
||||
return &dst
|
||||
}
|
||||
|
||||
func (b *bucket32) intersect(a *bucket32) int {
|
||||
a = a.cloneShallow() // clone a, since is is sorted below.
|
||||
a.sort()
|
||||
b.sort()
|
||||
itemsCount := 0
|
||||
i := 0
|
||||
j := 0
|
||||
for {
|
||||
for i < len(b.b16his) && j < len(a.b16his) && b.b16his[i] < a.b16his[j] {
|
||||
b.buckets[i] = bucket16{}
|
||||
i++
|
||||
}
|
||||
if i >= len(b.b16his) {
|
||||
break
|
||||
}
|
||||
for j < len(a.b16his) && a.b16his[j] < b.b16his[i] {
|
||||
j++
|
||||
}
|
||||
if j >= len(a.b16his) {
|
||||
for i < len(b.b16his) {
|
||||
b.buckets[i] = bucket16{}
|
||||
i++
|
||||
}
|
||||
break
|
||||
}
|
||||
if b.b16his[i] == a.b16his[j] {
|
||||
itemsCount += b.buckets[i].intersect(&a.buckets[j])
|
||||
i++
|
||||
j++
|
||||
}
|
||||
}
|
||||
return itemsCount
|
||||
}
|
||||
|
||||
func (b *bucket32) forEach(f func(part []uint64) bool) bool {
|
||||
xbuf := partBufPool.Get().(*[]uint64)
|
||||
buf := *xbuf
|
||||
for i := range b.buckets {
|
||||
hi16 := b.b16his[i]
|
||||
buf = b.buckets[i].appendTo(buf[:0], b.hi, hi16)
|
||||
if !f(buf) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
*xbuf = buf
|
||||
partBufPool.Put(xbuf)
|
||||
return true
|
||||
}
|
||||
|
||||
var partBufPool = &sync.Pool{
|
||||
New: func() interface{} {
|
||||
buf := make([]uint64, 0, bitsPerBucket)
|
||||
return &buf
|
||||
},
|
||||
}
|
||||
|
||||
func (b *bucket32) sizeBytes() uint64 {
|
||||
@@ -240,6 +368,7 @@ func (b *bucket32) copyTo(dst *bucket32) {
|
||||
b.buckets[i].copyTo(&dst.buckets[i])
|
||||
}
|
||||
}
|
||||
dst.hint = b.hint
|
||||
}
|
||||
|
||||
// This is for sort.Interface
|
||||
@@ -257,11 +386,26 @@ const maxUnsortedBuckets = 32
|
||||
func (b *bucket32) add(x uint32) bool {
|
||||
hi := uint16(x >> 16)
|
||||
lo := uint16(x)
|
||||
if n := b.hint; n < len(b.b16his) && b.b16his[n] == hi {
|
||||
// Fast path - add to the previously used bucket.
|
||||
return n < len(b.buckets) && b.buckets[n].add(lo)
|
||||
}
|
||||
return b.addSlow(hi, lo)
|
||||
}
|
||||
|
||||
func (b *bucket32) addSlow(hi, lo uint16) bool {
|
||||
if len(b.buckets) > maxUnsortedBuckets {
|
||||
return b.addSlow(hi, lo)
|
||||
n := binarySearch16(b.b16his, hi)
|
||||
b.hint = n
|
||||
if n < 0 || n >= len(b.b16his) || b.b16his[n] != hi {
|
||||
b.addAllocBig(hi, lo, n)
|
||||
return true
|
||||
}
|
||||
return n < len(b.buckets) && b.buckets[n].add(lo)
|
||||
}
|
||||
for i, hi16 := range b.b16his {
|
||||
if hi16 == hi {
|
||||
b.hint = i
|
||||
return i < len(b.buckets) && b.buckets[i].add(lo)
|
||||
}
|
||||
}
|
||||
@@ -283,15 +427,6 @@ func (b *bucket32) addBucket16() *bucket16 {
|
||||
return &b.buckets[len(b.buckets)-1]
|
||||
}
|
||||
|
||||
func (b *bucket32) addSlow(hi, lo uint16) bool {
|
||||
n := binarySearch16(b.b16his, hi)
|
||||
if n < 0 || n >= len(b.b16his) || b.b16his[n] != hi {
|
||||
b.addAllocBig(hi, lo, n)
|
||||
return true
|
||||
}
|
||||
return n < len(b.buckets) && b.buckets[n].add(lo)
|
||||
}
|
||||
|
||||
func (b *bucket32) addAllocBig(hi, lo uint16, n int) {
|
||||
if n < 0 {
|
||||
// This is a hint to Go compiler to remove automatic bounds checks below.
|
||||
@@ -336,28 +471,34 @@ func (b *bucket32) hasSlow(hi, lo uint16) bool {
|
||||
func (b *bucket32) del(x uint32) bool {
|
||||
hi := uint16(x >> 16)
|
||||
lo := uint16(x)
|
||||
if n := b.hint; n < len(b.b16his) && b.b16his[n] == hi {
|
||||
// Fast path - use the bucket from the previous operation.
|
||||
return n < len(b.buckets) && b.buckets[n].del(lo)
|
||||
}
|
||||
return b.delSlow(hi, lo)
|
||||
}
|
||||
|
||||
func (b *bucket32) delSlow(hi, lo uint16) bool {
|
||||
if len(b.buckets) > maxUnsortedBuckets {
|
||||
return b.delSlow(hi, lo)
|
||||
n := binarySearch16(b.b16his, hi)
|
||||
b.hint = n
|
||||
if n < 0 || n >= len(b.b16his) || b.b16his[n] != hi {
|
||||
return false
|
||||
}
|
||||
return n < len(b.buckets) && b.buckets[n].del(lo)
|
||||
}
|
||||
for i, hi16 := range b.b16his {
|
||||
if hi16 == hi {
|
||||
b.hint = i
|
||||
return i < len(b.buckets) && b.buckets[i].del(lo)
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (b *bucket32) delSlow(hi, lo uint16) bool {
|
||||
n := binarySearch16(b.b16his, hi)
|
||||
if n < 0 || n >= len(b.b16his) || b.b16his[n] != hi {
|
||||
return false
|
||||
}
|
||||
return n < len(b.buckets) && b.buckets[n].del(lo)
|
||||
}
|
||||
|
||||
func (b *bucket32) appendTo(dst []uint64) []uint64 {
|
||||
if len(b.buckets) <= maxUnsortedBuckets && !sort.IsSorted(b) {
|
||||
sort.Sort(b)
|
||||
if len(b.buckets) <= maxUnsortedBuckets {
|
||||
b.sort()
|
||||
}
|
||||
for i := range b.buckets {
|
||||
hi16 := b.b16his[i]
|
||||
@@ -366,6 +507,12 @@ func (b *bucket32) appendTo(dst []uint64) []uint64 {
|
||||
return dst
|
||||
}
|
||||
|
||||
func (b *bucket32) sort() {
|
||||
if !sort.IsSorted(b) {
|
||||
sort.Sort(b)
|
||||
}
|
||||
}
|
||||
|
||||
const (
|
||||
bitsPerBucket = 1 << 16
|
||||
wordsPerBucket = bitsPerBucket / 64
|
||||
@@ -377,6 +524,38 @@ type bucket16 struct {
|
||||
smallPool [56]uint16
|
||||
}
|
||||
|
||||
func (b *bucket16) intersect(a *bucket16) int {
|
||||
itemsCount := 0
|
||||
if a.bits != nil && b.bits != nil {
|
||||
// Fast path - use bitwise ops
|
||||
for i, ax := range a.bits {
|
||||
bx := b.bits[i]
|
||||
bx &= ax
|
||||
if bx > 0 {
|
||||
itemsCount += bits.OnesCount64(bx)
|
||||
}
|
||||
b.bits[i] = bx
|
||||
}
|
||||
return itemsCount
|
||||
}
|
||||
|
||||
// Slow path
|
||||
xbuf := partBufPool.Get().(*[]uint64)
|
||||
buf := *xbuf
|
||||
buf = b.appendTo(buf[:0], 0, 0)
|
||||
itemsCount = len(buf)
|
||||
for _, x := range buf {
|
||||
x16 := uint16(x)
|
||||
if !a.has(x16) {
|
||||
b.del(x16)
|
||||
itemsCount--
|
||||
}
|
||||
}
|
||||
*xbuf = buf
|
||||
partBufPool.Put(xbuf)
|
||||
return itemsCount
|
||||
}
|
||||
|
||||
func (b *bucket16) sizeBytes() uint64 {
|
||||
return uint64(unsafe.Sizeof(*b)) + uint64(unsafe.Sizeof(*b.bits))
|
||||
}
|
||||
|
||||
@@ -166,6 +166,48 @@ func testSetBasicOps(t *testing.T, itemsCount int) {
|
||||
}
|
||||
}
|
||||
|
||||
// Verify ForEach
|
||||
{
|
||||
var s Set
|
||||
m := make(map[uint64]bool)
|
||||
for i := 0; i < itemsCount; i++ {
|
||||
v := uint64(i) + offset
|
||||
s.Add(v)
|
||||
m[v] = true
|
||||
}
|
||||
|
||||
// Verify visiting all the items.
|
||||
s.ForEach(func(part []uint64) bool {
|
||||
for _, v := range part {
|
||||
if !m[v] {
|
||||
t.Fatalf("unexpected value v=%d passed to ForEach", v)
|
||||
}
|
||||
delete(m, v)
|
||||
}
|
||||
return true
|
||||
})
|
||||
if len(m) != 0 {
|
||||
t.Fatalf("ForEach didn't visit %d items; items: %v", len(m), m)
|
||||
}
|
||||
|
||||
// Verify fast stop
|
||||
calls := 0
|
||||
s.ForEach(func(part []uint64) bool {
|
||||
calls++
|
||||
return false
|
||||
})
|
||||
if itemsCount > 0 && calls != 1 {
|
||||
t.Fatalf("Unexpected number of ForEach callback calls; got %d; want %d", calls, 1)
|
||||
}
|
||||
|
||||
// Verify ForEach on nil set.
|
||||
var s1 *Set
|
||||
s1.ForEach(func(part []uint64) bool {
|
||||
t.Fatalf("callback shouldn't be called on empty set")
|
||||
return true
|
||||
})
|
||||
}
|
||||
|
||||
// Verify union
|
||||
{
|
||||
const unionOffset = 12345
|
||||
@@ -190,32 +232,52 @@ func testSetBasicOps(t *testing.T, itemsCount int) {
|
||||
if n := s3.Len(); n != expectedLen {
|
||||
t.Fatalf("unexpected s3.Len() after union with empty set; got %d; want %d", n, expectedLen)
|
||||
}
|
||||
var s4 Set
|
||||
expectedLen = s3.Len()
|
||||
s3.Union(&s4)
|
||||
if n := s3.Len(); n != expectedLen {
|
||||
t.Fatalf("unexpected s3.Len() after union with empty set; got %d; want %d", n, expectedLen)
|
||||
}
|
||||
}
|
||||
|
||||
// Verify intersect
|
||||
{
|
||||
const intersectOffset = 12345
|
||||
// Verify s1.Intersect(s2) and s2.Intersect(s1)
|
||||
var s1, s2 Set
|
||||
for i := 0; i < itemsCount; i++ {
|
||||
s1.Add(uint64(i) + offset)
|
||||
s2.Add(uint64(i) + offset + intersectOffset)
|
||||
}
|
||||
s1.Intersect(&s2)
|
||||
expectedLen := 0
|
||||
if itemsCount > intersectOffset {
|
||||
expectedLen = itemsCount - intersectOffset
|
||||
}
|
||||
if n := s1.Len(); n != expectedLen {
|
||||
t.Fatalf("unexpected s1.Len() after intersect; got %d; want %d", n, expectedLen)
|
||||
for _, intersectOffset := range []uint64{123, 12345, 1<<32 + 4343} {
|
||||
s1 = Set{}
|
||||
s2 = Set{}
|
||||
for i := 0; i < itemsCount; i++ {
|
||||
s1.Add(uint64(i) + offset)
|
||||
s2.Add(uint64(i) + offset + intersectOffset)
|
||||
}
|
||||
expectedLen := 0
|
||||
if uint64(itemsCount) > intersectOffset {
|
||||
expectedLen = int(uint64(itemsCount) - intersectOffset)
|
||||
}
|
||||
s1Copy := s1.Clone()
|
||||
s1Copy.Intersect(&s2)
|
||||
if n := s1Copy.Len(); n != expectedLen {
|
||||
t.Fatalf("unexpected s1.Len() after intersect; got %d; want %d", n, expectedLen)
|
||||
}
|
||||
s2.Intersect(&s1)
|
||||
if n := s2.Len(); n != expectedLen {
|
||||
t.Fatalf("unexpected s2.Len() after intersect; got %d; want %d", n, expectedLen)
|
||||
}
|
||||
}
|
||||
|
||||
// Verify intersect on empty set.
|
||||
var s3 Set
|
||||
s2.Intersect(&s3)
|
||||
expectedLen = 0
|
||||
if n := s2.Len(); n != 0 {
|
||||
expectedLen := 0
|
||||
if n := s2.Len(); n != expectedLen {
|
||||
t.Fatalf("unexpected s3.Len() after intersect with empty set; got %d; want %d", n, expectedLen)
|
||||
}
|
||||
var s4 Set
|
||||
s4.Intersect(&s1)
|
||||
if n := s4.Len(); n != expectedLen {
|
||||
t.Fatalf("unexpected s4.Len() after intersect with empty set; got %d; want %d", n, expectedLen)
|
||||
}
|
||||
}
|
||||
|
||||
// Verify subtract
|
||||
|
||||
@@ -8,6 +8,61 @@ import (
|
||||
"github.com/valyala/fastrand"
|
||||
)
|
||||
|
||||
func BenchmarkIntersectNoOverlap(b *testing.B) {
|
||||
for _, itemsCount := range []int{1e3, 1e4, 1e5, 1e6, 1e7} {
|
||||
start := uint64(time.Now().UnixNano())
|
||||
sa := createRangeSet(start, itemsCount)
|
||||
sb := createRangeSet(start+uint64(itemsCount), itemsCount)
|
||||
b.Run(fmt.Sprintf("items_%d", itemsCount), func(b *testing.B) {
|
||||
benchmarkIntersect(b, sa, sb)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkIntersectPartialOverlap(b *testing.B) {
|
||||
for _, itemsCount := range []int{1e3, 1e4, 1e5, 1e6, 1e7} {
|
||||
start := uint64(time.Now().UnixNano())
|
||||
sa := createRangeSet(start, itemsCount)
|
||||
sb := createRangeSet(start+uint64(itemsCount/2), itemsCount)
|
||||
b.Run(fmt.Sprintf("items_%d", itemsCount), func(b *testing.B) {
|
||||
benchmarkIntersect(b, sa, sb)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkIntersectFullOverlap(b *testing.B) {
|
||||
for _, itemsCount := range []int{1e3, 1e4, 1e5, 1e6, 1e7} {
|
||||
start := uint64(time.Now().UnixNano())
|
||||
sa := createRangeSet(start, itemsCount)
|
||||
sb := createRangeSet(start, itemsCount)
|
||||
b.Run(fmt.Sprintf("items_%d", itemsCount), func(b *testing.B) {
|
||||
benchmarkIntersect(b, sa, sb)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func benchmarkIntersect(b *testing.B, sa, sb *Set) {
|
||||
b.ReportAllocs()
|
||||
b.SetBytes(int64(sa.Len() + sb.Len()))
|
||||
b.RunParallel(func(pb *testing.PB) {
|
||||
for pb.Next() {
|
||||
saCopy := sa.Clone()
|
||||
sbCopy := sb.Clone()
|
||||
saCopy.Intersect(sb)
|
||||
sbCopy.Intersect(sa)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func createRangeSet(start uint64, itemsCount int) *Set {
|
||||
var s Set
|
||||
for i := 0; i < itemsCount; i++ {
|
||||
n := start + uint64(i)
|
||||
s.Add(n)
|
||||
}
|
||||
return &s
|
||||
}
|
||||
|
||||
func BenchmarkSetAddRandomLastBits(b *testing.B) {
|
||||
const itemsCount = 1e5
|
||||
for _, lastBits := range []uint64{20, 24, 28, 32} {
|
||||
@@ -16,10 +71,10 @@ func BenchmarkSetAddRandomLastBits(b *testing.B) {
|
||||
b.ReportAllocs()
|
||||
b.SetBytes(int64(itemsCount))
|
||||
b.RunParallel(func(pb *testing.PB) {
|
||||
var rng fastrand.RNG
|
||||
for pb.Next() {
|
||||
start := uint64(time.Now().UnixNano())
|
||||
var s Set
|
||||
var rng fastrand.RNG
|
||||
for i := 0; i < itemsCount; i++ {
|
||||
n := start | (uint64(rng.Uint32()) & mask)
|
||||
s.Add(n)
|
||||
@@ -38,10 +93,10 @@ func BenchmarkMapAddRandomLastBits(b *testing.B) {
|
||||
b.ReportAllocs()
|
||||
b.SetBytes(int64(itemsCount))
|
||||
b.RunParallel(func(pb *testing.PB) {
|
||||
var rng fastrand.RNG
|
||||
for pb.Next() {
|
||||
start := uint64(time.Now().UnixNano())
|
||||
m := make(map[uint64]struct{})
|
||||
var rng fastrand.RNG
|
||||
for i := 0; i < itemsCount; i++ {
|
||||
n := start | (uint64(rng.Uint32()) & mask)
|
||||
m[n] = struct{}{}
|
||||
|
||||
8
vendor/cloud.google.com/go/CHANGES.md
generated
vendored
8
vendor/cloud.google.com/go/CHANGES.md
generated
vendored
@@ -1,5 +1,13 @@
|
||||
# Changes
|
||||
|
||||
## v0.51.0
|
||||
|
||||
- secretmanager:
|
||||
- add IAM helper for generic resource IAM handle
|
||||
- cloudbuild:
|
||||
- migrate to microgen in a major version
|
||||
- Various updates to autogenerated clients.
|
||||
|
||||
## v0.50.0
|
||||
|
||||
- profiler:
|
||||
|
||||
26
vendor/cloud.google.com/go/go.mod
generated
vendored
26
vendor/cloud.google.com/go/go.mod
generated
vendored
@@ -7,24 +7,26 @@ require (
|
||||
cloud.google.com/go/datastore v1.0.0
|
||||
cloud.google.com/go/pubsub v1.0.1
|
||||
cloud.google.com/go/storage v1.0.0
|
||||
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7 // indirect
|
||||
github.com/golang/mock v1.3.1
|
||||
github.com/golang/protobuf v1.3.2
|
||||
github.com/google/go-cmp v0.3.0
|
||||
github.com/google/go-cmp v0.3.1
|
||||
github.com/google/martian v2.1.0+incompatible
|
||||
github.com/google/pprof v0.0.0-20190515194954-54271f7e092f
|
||||
github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc
|
||||
github.com/googleapis/gax-go/v2 v2.0.5
|
||||
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024
|
||||
go.opencensus.io v0.22.0
|
||||
golang.org/x/exp v0.0.0-20191129062945-2f5052295587
|
||||
github.com/jstemmer/go-junit-report v0.9.1
|
||||
go.opencensus.io v0.22.2
|
||||
golang.org/x/exp v0.0.0-20191227195350-da58074b4299
|
||||
golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f
|
||||
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45
|
||||
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553
|
||||
golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6
|
||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e // indirect
|
||||
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e // indirect
|
||||
golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8 // indirect
|
||||
golang.org/x/text v0.3.2
|
||||
golang.org/x/tools v0.0.0-20191216173652-a0e659d51361
|
||||
google.golang.org/api v0.14.0
|
||||
google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1
|
||||
google.golang.org/grpc v1.21.1
|
||||
golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4
|
||||
google.golang.org/api v0.15.0
|
||||
google.golang.org/appengine v1.6.5 // indirect
|
||||
google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb
|
||||
google.golang.org/grpc v1.26.0
|
||||
honnef.co/go/tools v0.0.1-2019.2.3
|
||||
)
|
||||
|
||||
59
vendor/cloud.google.com/go/go.sum
generated
vendored
59
vendor/cloud.google.com/go/go.sum
generated
vendored
@@ -17,10 +17,20 @@ dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7
|
||||
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
|
||||
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
|
||||
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7 h1:5ZkaAPbicIKTF2I64qf5Fh8Aa83Q/dnOafMYV0OMwjA=
|
||||
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/mock v1.2.0 h1:28o5sBqPkBsMGnC6b4MvE2TzSr5/AT4c/1fLqVGIwlk=
|
||||
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
@@ -39,12 +49,16 @@ github.com/google/go-cmp v0.2.0 h1:+dTQ8DZQJz0Mb/HjFlkptS1FeQ4cWSnN941F8aEG4SQ=
|
||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||
github.com/google/go-cmp v0.3.0 h1:crn/baboCvb5fXaQ0IJ1SGTsTVrWpDsCWC8EGETZijY=
|
||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.3.1 h1:Xye71clBPdm5HgqGwUkwhbynsUJZhDbS20FvLhQ2izg=
|
||||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/martian v2.1.0+incompatible h1:/CP5g8u/VJHijgedC/Legn3BAbAaWPgecwXBIDzw5no=
|
||||
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
|
||||
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57 h1:eqyIo2HjKhKe/mJzTG8n4VqvLXIOEG+SLdDqX7xGtkY=
|
||||
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||
github.com/google/pprof v0.0.0-20190515194954-54271f7e092f h1:Jnx61latede7zDD3DiiP4gmNz33uK0U5HDUaF0a/HVQ=
|
||||
github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||
github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc h1:DLpL8pWq0v4JYoRpEhDfsJhhJyGKCcQM2WPW2TJs31c=
|
||||
github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||
github.com/googleapis/gax-go/v2 v2.0.4 h1:hU4mGcQI4DaAYW+IbTun+2qEZVFxK0ySjQLTbS0VQKc=
|
||||
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
|
||||
@@ -54,19 +68,28 @@ github.com/hashicorp/golang-lru v0.5.0 h1:CL2msUPvZTLb5O648aiLNJw3hnBxN2+1Jq8rCO
|
||||
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/hashicorp/golang-lru v0.5.1 h1:0hERBMJE1eitiLkihrMvRVBYAkpHzc/J3QdDN+dAcgU=
|
||||
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024 h1:rBMNdlhTLzJjJSDIjNEXX1Pz3Hmwmz91v+zycvx9PJc=
|
||||
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
||||
github.com/jstemmer/go-junit-report v0.9.1 h1:6QPYqodiu3GuPL+7mfx+NwDdp2eTkp9IfEUpgAwUN0o=
|
||||
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
go.opencensus.io v0.21.0 h1:mU6zScU4U1YAFPHEHYk+3JC4SY7JxgkqS10ZOSyksNg=
|
||||
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
|
||||
go.opencensus.io v0.22.0 h1:C9hSCOW830chIVkdja34wa6Ky+IzWllkUinR+BtRZd4=
|
||||
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
|
||||
go.opencensus.io v0.22.2 h1:75k/FF0Q2YM8QYo07VPddOLBslDt1MZOdEslOHvmzAs=
|
||||
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
@@ -78,8 +101,8 @@ golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522 h1:OeRHuibLsmZkFj773W4LcfAGs
|
||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||
golang.org/x/exp v0.0.0-20190829153037-c13cbed26979 h1:Agxu5KLo8o7Bb634SVDnhIfpTvxmzUwhbYAzBvXt6h4=
|
||||
golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=
|
||||
golang.org/x/exp v0.0.0-20191129062945-2f5052295587 h1:5Uz0rkjCFu9BC9gCRN7EkwVvhNyQgGWb8KNJrPwBoHY=
|
||||
golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
|
||||
golang.org/x/exp v0.0.0-20191227195350-da58074b4299 h1:zQpM52jfKHG6II1ISZY1ZcpygvuSFZpLwfluuF89XOg=
|
||||
golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
|
||||
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
||||
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
@@ -111,13 +134,15 @@ golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn
|
||||
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859 h1:R/3boaszxrf1GEUWTVDzSKVwLmSJpwZ1yqXm8j0v2QI=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80 h1:Ao/3l156eZf2AW5wK8a7/smtodRU+gha3+BeqJ69lRk=
|
||||
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553 h1:efeOvDhwQ29Dj3SdAV/MJf8oukgn+8D8WgaCaRMchF8=
|
||||
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421 h1:Wo7BWFiOk0QRFMLYMqJGFMd9CgUAcGx7V+qEg/h5IBI=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45 h1:SVwTIAaPC2U/AvvLNZ2a7OVsmBpC8L5BlwK1whH3hm0=
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6 h1:pE8b58s1HRDMi8RDc79m0HISf9D4TzseP40cEA6IGfs=
|
||||
golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
@@ -138,8 +163,9 @@ golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0 h1:HyfiK1WMnHj5FXFXatD+Qs1A/xC2Run6RzeW1SyHxpc=
|
||||
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e h1:D5TXcfTk7xF7hvieo4QErS3qqCB4teTffacDWr7CI+0=
|
||||
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8 h1:JA8d3MPx/IToSyXZG/RhwYEtfrKO1Fxrqe8KrkiLXKM=
|
||||
golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2 h1:z99zHgr7hKfrUcX/KsoJk5FJfjTceCKIp96+biqP4To=
|
||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
@@ -159,6 +185,7 @@ golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3
|
||||
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c h1:97SnQk1GYRXJgvwZ8fadnxDOWfKvkNQHH3CtZntPSrM=
|
||||
golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0 h1:Dh6fw+p6FyRl5x/FvNswO1ji0lIGzm3KP8Y9VkS9PTE=
|
||||
@@ -168,8 +195,8 @@ golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff h1:On1qIo75ByTwFJ4/W2bIqHc
|
||||
golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191216173652-a0e659d51361 h1:RIIXAeV6GvDBuADKumTODatUqANFZ+5BPMnzsy4hulY=
|
||||
golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4 h1:Toz2IK7k8rbltAXwNAxKcn9OzqyNfMUhUNjz3sL0NMk=
|
||||
golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
|
||||
@@ -178,8 +205,8 @@ google.golang.org/api v0.8.0 h1:VGGbLNyPF7dvYHhcUGYBBGCRDDK0RRJAI6KCvo0CL+E=
|
||||
google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
|
||||
google.golang.org/api v0.9.0 h1:jbyannxz0XFD3zdjgrSUsaJbgpH4eTrkdhRChkHPfO8=
|
||||
google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
|
||||
google.golang.org/api v0.14.0 h1:uMf5uLi4eQMRrMKhCplNik4U4H8Z6C1br3zOtAa/aDE=
|
||||
google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
|
||||
google.golang.org/api v0.15.0 h1:yzlyyDW/J0w8yNFJIhiAJy4kq74S+1DOLdawELNxFMA=
|
||||
google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
|
||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||
google.golang.org/appengine v1.4.0 h1:/wp5JvzpHIxhs/dumFmF7BXTf3Z+dd4uXta4kVyO508=
|
||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
@@ -187,6 +214,8 @@ google.golang.org/appengine v1.5.0 h1:KxkO13IPW4Lslp2bz+KHP2E3gtFlrIGNThxkZQ3g+4
|
||||
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.6.1 h1:QzqyMA1tlu6CgqCDUtU9V+ZKhLFT2dkJuANu5QaxI3I=
|
||||
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
|
||||
google.golang.org/appengine v1.6.5 h1:tycE03LOZYQNhDpS27tcQdAzLCVMaj7QT2SXxebnpCM=
|
||||
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19 h1:Lj2SnHtxkRGJDqnGaSjo+CCdIieEnwVazbOXILwQemk=
|
||||
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
@@ -200,22 +229,28 @@ google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55 h1:gSJIx1SDwno+2El
|
||||
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||
google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51 h1:Ex1mq5jaJof+kRnYi3SlYJ8KKa9Ao3NHyIT5XJ1gF6U=
|
||||
google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
|
||||
google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1 h1:aQktFqmDE2yjveXJlVIfslDFmFnUXSqG0i6KRcJAeMc=
|
||||
google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb h1:ADPHZzpzM4tk4V4S5cnCrr5SwzvlrPRmqqCuJDB8UTs=
|
||||
google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/grpc v1.19.0 h1:cfg4PD8YEdSFnm7qLV4++93WcmhH2nIUhMjhdCvl3j8=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
google.golang.org/grpc v1.20.1 h1:Hz2g2wirWK7H0qIIhGIqRGTuMwTE8HEKFnDZZ7lm9NU=
|
||||
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
|
||||
google.golang.org/grpc v1.21.1 h1:j6XxA85m/6txkUCHvzlV5f+HBNl/1r5cZ2A/3IEFOO8=
|
||||
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
||||
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||
google.golang.org/grpc v1.26.0 h1:2dTRdpdFEEhJYQD8EMLB61nnrzSCTbG38PhqdhvOltg=
|
||||
google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a h1:/8zB6iBfHCl1qAnEAWwGPNrUvapuy6CPla1VM0k8hQw=
|
||||
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a h1:LJwr7TCTghdatWv40WobzlKXc9c4s8oGa7QKJUtHhWA=
|
||||
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM=
|
||||
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
|
||||
rsc.io/binaryregexp v0.2.0 h1:HfqmD5MEmC0zvwBuF187nq9mdnXjXsSivRiXN7SmRkE=
|
||||
|
||||
8
vendor/cloud.google.com/go/storage/CHANGES.md
generated
vendored
8
vendor/cloud.google.com/go/storage/CHANGES.md
generated
vendored
@@ -1,5 +1,11 @@
|
||||
# Changes
|
||||
|
||||
## v1.5.0
|
||||
|
||||
- Honor WithEndpoint client option for reads as well as writes.
|
||||
- Add archive storage class to docs.
|
||||
- Make fixes to storage benchwrapper.
|
||||
|
||||
## v1.4.0
|
||||
|
||||
- When listing objects in a bucket, allow callers to specify which attributes
|
||||
@@ -40,4 +46,4 @@
|
||||
## v1.0.0
|
||||
|
||||
This is the first tag to carve out storage as its own module. See:
|
||||
https://github.com/golang/go/wiki/Modules#is-it-possible-to-add-a-module-to-a-multi-module-repository.
|
||||
https://github.com/golang/go/wiki/Modules#is-it-possible-to-add-a-module-to-a-multi-module-repository.
|
||||
|
||||
8
vendor/cloud.google.com/go/storage/bucket.go
generated
vendored
8
vendor/cloud.google.com/go/storage/bucket.go
generated
vendored
@@ -275,8 +275,10 @@ type BucketAttrs struct {
|
||||
|
||||
// StorageClass is the default storage class of the bucket. This defines
|
||||
// how objects in the bucket are stored and determines the SLA
|
||||
// and the cost of storage. Typical values are "NEARLINE", "COLDLINE" and
|
||||
// "STANDARD". Defaults to "STANDARD".
|
||||
// and the cost of storage. Typical values are "STANDARD", "NEARLINE",
|
||||
// "COLDLINE" and "ARCHIVE". Defaults to "STANDARD".
|
||||
// See https://cloud.google.com/storage/docs/storage-classes for all
|
||||
// valid values.
|
||||
StorageClass string
|
||||
|
||||
// Created is the creation time of the bucket.
|
||||
@@ -459,7 +461,7 @@ type LifecycleCondition struct {
|
||||
// MatchesStorageClasses is the condition matching the object's storage
|
||||
// class.
|
||||
//
|
||||
// Values include "NEARLINE", "COLDLINE" and "STANDARD".
|
||||
// Values include "STANDARD", "NEARLINE", "COLDLINE" and "ARCHIVE".
|
||||
MatchesStorageClasses []string
|
||||
|
||||
// NumNewerVersions is the condition matching objects with a number of newer versions.
|
||||
|
||||
25
vendor/cloud.google.com/go/storage/go.mod
generated
vendored
25
vendor/cloud.google.com/go/storage/go.mod
generated
vendored
@@ -3,15 +3,22 @@ module cloud.google.com/go/storage
|
||||
go 1.11
|
||||
|
||||
require (
|
||||
cloud.google.com/go v0.46.3
|
||||
cloud.google.com/go v0.50.0
|
||||
cloud.google.com/go/bigquery v1.3.0 // indirect
|
||||
cloud.google.com/go/pubsub v1.1.0 // indirect
|
||||
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7 // indirect
|
||||
github.com/golang/protobuf v1.3.2
|
||||
github.com/google/go-cmp v0.3.0
|
||||
github.com/google/go-cmp v0.3.1
|
||||
github.com/googleapis/gax-go/v2 v2.0.5
|
||||
golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136 // indirect
|
||||
golang.org/x/lint v0.0.0-20190930215403-16217165b5de // indirect
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45
|
||||
golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2 // indirect
|
||||
google.golang.org/api v0.14.0
|
||||
google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9
|
||||
google.golang.org/grpc v1.21.1
|
||||
github.com/jstemmer/go-junit-report v0.9.1 // indirect
|
||||
go.opencensus.io v0.22.2 // indirect
|
||||
golang.org/x/exp v0.0.0-20191227195350-da58074b4299 // indirect
|
||||
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553 // indirect
|
||||
golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6
|
||||
golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8 // indirect
|
||||
golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4 // indirect
|
||||
google.golang.org/api v0.15.0
|
||||
google.golang.org/appengine v1.6.5 // indirect
|
||||
google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb
|
||||
google.golang.org/grpc v1.26.0
|
||||
)
|
||||
|
||||
70
vendor/cloud.google.com/go/storage/go.sum
generated
vendored
70
vendor/cloud.google.com/go/storage/go.sum
generated
vendored
@@ -6,20 +6,35 @@ cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxK
|
||||
cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=
|
||||
cloud.google.com/go v0.46.3 h1:AVXDdKsrtX33oR9fbCMu/+c1o8Ofjq6Ku/MInaLVg5Y=
|
||||
cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=
|
||||
cloud.google.com/go v0.50.0 h1:0E3eE8MX426vUOs7aHfI7aN1BrIzzzf4ccKCSfSjGmc=
|
||||
cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To=
|
||||
cloud.google.com/go/bigquery v1.0.1 h1:hL+ycaJpVE9M7nLoiXb/Pn10ENE2u+oddxbD8uu0ZVU=
|
||||
cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
|
||||
cloud.google.com/go/bigquery v1.3.0 h1:sAbMqjY1PEQKZBWfbu6Y6bsupJ9c4QdHnzg/VvYTLcE=
|
||||
cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
|
||||
cloud.google.com/go/datastore v1.0.0 h1:Kt+gOPPp2LEPWp8CSfxhsM8ik9CcyE/gYu+0r+RnZvM=
|
||||
cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
|
||||
cloud.google.com/go/pubsub v1.0.1 h1:W9tAK3E57P75u0XLLR82LZyw8VpAnhmyTOxW9qzmyj8=
|
||||
cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
|
||||
cloud.google.com/go/pubsub v1.1.0 h1:9/vpR43S4aJaROxqQHQ3nH9lfyKKV0dC3vOmnw8ebQQ=
|
||||
cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=
|
||||
cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
|
||||
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
|
||||
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7 h1:5ZkaAPbicIKTF2I64qf5Fh8Aa83Q/dnOafMYV0OMwjA=
|
||||
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
|
||||
@@ -32,6 +47,8 @@ github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ
|
||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||
github.com/google/go-cmp v0.3.0 h1:crn/baboCvb5fXaQ0IJ1SGTsTVrWpDsCWC8EGETZijY=
|
||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.3.1 h1:Xye71clBPdm5HgqGwUkwhbynsUJZhDbS20FvLhQ2izg=
|
||||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/martian v2.1.0+incompatible h1:/CP5g8u/VJHijgedC/Legn3BAbAaWPgecwXBIDzw5no=
|
||||
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
|
||||
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||
@@ -45,24 +62,36 @@ github.com/hashicorp/golang-lru v0.5.1 h1:0hERBMJE1eitiLkihrMvRVBYAkpHzc/J3QdDN+
|
||||
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024 h1:rBMNdlhTLzJjJSDIjNEXX1Pz3Hmwmz91v+zycvx9PJc=
|
||||
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
||||
github.com/jstemmer/go-junit-report v0.9.1 h1:6QPYqodiu3GuPL+7mfx+NwDdp2eTkp9IfEUpgAwUN0o=
|
||||
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
|
||||
go.opencensus.io v0.22.0 h1:C9hSCOW830chIVkdja34wa6Ky+IzWllkUinR+BtRZd4=
|
||||
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
|
||||
go.opencensus.io v0.22.2 h1:75k/FF0Q2YM8QYo07VPddOLBslDt1MZOdEslOHvmzAs=
|
||||
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||
golang.org/x/exp v0.0.0-20190829153037-c13cbed26979 h1:Agxu5KLo8o7Bb634SVDnhIfpTvxmzUwhbYAzBvXt6h4=
|
||||
golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=
|
||||
golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136 h1:A1gGSx58LAGVHUUsOf7IiR0u8Xb6W51gRwfDBhkdcaw=
|
||||
golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=
|
||||
golang.org/x/exp v0.0.0-20191129062945-2f5052295587 h1:5Uz0rkjCFu9BC9gCRN7EkwVvhNyQgGWb8KNJrPwBoHY=
|
||||
golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
|
||||
golang.org/x/exp v0.0.0-20191227195350-da58074b4299 h1:zQpM52jfKHG6II1ISZY1ZcpygvuSFZpLwfluuF89XOg=
|
||||
golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
|
||||
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
||||
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
@@ -72,12 +101,14 @@ golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHl
|
||||
golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac h1:8R1esu+8QioDxo4E4mX6bFztO+dMTM49DNAaWfO5OeY=
|
||||
golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20190930215403-16217165b5de h1:5hukYrvBGR8/eNkX5mdUezrA6JiaEZDtJb9Ei+1LlBs=
|
||||
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f h1:J5lckAjkw6qYlOZNj90mLYNTEKDvWeuc1yieZ8qUzUE=
|
||||
golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=
|
||||
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
|
||||
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
|
||||
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
|
||||
golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
|
||||
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
@@ -89,16 +120,23 @@ golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn
|
||||
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859 h1:R/3boaszxrf1GEUWTVDzSKVwLmSJpwZ1yqXm8j0v2QI=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553 h1:efeOvDhwQ29Dj3SdAV/MJf8oukgn+8D8WgaCaRMchF8=
|
||||
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45 h1:SVwTIAaPC2U/AvvLNZ2a7OVsmBpC8L5BlwK1whH3hm0=
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6 h1:pE8b58s1HRDMi8RDc79m0HISf9D4TzseP40cEA6IGfs=
|
||||
golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58 h1:8gQV6CLnAEikrhgkHFbMAEhagSSnXWGV915qUMm9mrU=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e h1:vcxGaoTs7kV8m5Np9uUNQin4BrLOthgV7252N8V+FwY=
|
||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
@@ -108,6 +146,9 @@ golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0 h1:HyfiK1WMnHj5FXFXatD+Qs1A/xC2Run6RzeW1SyHxpc=
|
||||
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8 h1:JA8d3MPx/IToSyXZG/RhwYEtfrKO1Fxrqe8KrkiLXKM=
|
||||
golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
|
||||
@@ -122,6 +163,7 @@ golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3
|
||||
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
@@ -129,21 +171,30 @@ golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtn
|
||||
golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff h1:On1qIo75ByTwFJ4/W2bIqHcwJ9XAqtSWUs8GwRrIhtc=
|
||||
golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2 h1:EtTFh6h4SAKemS+CURDMTDIANuduG5zKEXShyy18bGA=
|
||||
golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4 h1:Toz2IK7k8rbltAXwNAxKcn9OzqyNfMUhUNjz3sL0NMk=
|
||||
golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
|
||||
google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
|
||||
google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
|
||||
google.golang.org/api v0.9.0 h1:jbyannxz0XFD3zdjgrSUsaJbgpH4eTrkdhRChkHPfO8=
|
||||
google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
|
||||
google.golang.org/api v0.14.0 h1:uMf5uLi4eQMRrMKhCplNik4U4H8Z6C1br3zOtAa/aDE=
|
||||
google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
|
||||
google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
|
||||
google.golang.org/api v0.15.0 h1:yzlyyDW/J0w8yNFJIhiAJy4kq74S+1DOLdawELNxFMA=
|
||||
google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
|
||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.6.1 h1:QzqyMA1tlu6CgqCDUtU9V+ZKhLFT2dkJuANu5QaxI3I=
|
||||
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
|
||||
google.golang.org/appengine v1.6.5 h1:tycE03LOZYQNhDpS27tcQdAzLCVMaj7QT2SXxebnpCM=
|
||||
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
@@ -153,17 +204,26 @@ google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98
|
||||
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||
google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51 h1:Ex1mq5jaJof+kRnYi3SlYJ8KKa9Ao3NHyIT5XJ1gF6U=
|
||||
google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
|
||||
google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9 h1:6XzpBoANz1NqMNfDXzc2QmHmbb1vyMsvRfoP5rM+K1I=
|
||||
google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb h1:ADPHZzpzM4tk4V4S5cnCrr5SwzvlrPRmqqCuJDB8UTs=
|
||||
google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
|
||||
google.golang.org/grpc v1.21.1 h1:j6XxA85m/6txkUCHvzlV5f+HBNl/1r5cZ2A/3IEFOO8=
|
||||
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
||||
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||
google.golang.org/grpc v1.26.0 h1:2dTRdpdFEEhJYQD8EMLB61nnrzSCTbG38PhqdhvOltg=
|
||||
google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM=
|
||||
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
|
||||
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
|
||||
|
||||
22
vendor/cloud.google.com/go/storage/storage.go
generated
vendored
22
vendor/cloud.google.com/go/storage/storage.go
generated
vendored
@@ -121,7 +121,14 @@ func NewClient(ctx context.Context, opts ...option.ClientOption) (*Client, error
|
||||
// TODO: remove when the raw client uses this endpoint as its default (~end of 2020)
|
||||
rawService.BasePath = "https://storage.googleapis.com/storage/v1/"
|
||||
} else {
|
||||
// If the endpoint has been set explicitly, use this for the BasePath
|
||||
// as well as readHost
|
||||
rawService.BasePath = ep
|
||||
u, err := url.Parse(ep)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("supplied endpoint %v is not valid: %v", ep, err)
|
||||
}
|
||||
readHost = u.Hostname()
|
||||
}
|
||||
|
||||
return &Client{
|
||||
@@ -995,11 +1002,12 @@ type ObjectAttrs struct {
|
||||
// of a particular object. This field is read-only.
|
||||
Metageneration int64
|
||||
|
||||
// StorageClass is the storage class of the object.
|
||||
// This value defines how objects in the bucket are stored and
|
||||
// determines the SLA and the cost of storage. Typical values are
|
||||
// "NEARLINE", "COLDLINE" and "STANDARD".
|
||||
// It defaults to "STANDARD".
|
||||
// StorageClass is the storage class of the object. This defines
|
||||
// how objects are stored and determines the SLA and the cost of storage.
|
||||
// Typical values are "STANDARD", "NEARLINE", "COLDLINE" and "ARCHIVE".
|
||||
// Defaults to "STANDARD".
|
||||
// See https://cloud.google.com/storage/docs/storage-classes for all
|
||||
// valid values.
|
||||
StorageClass string
|
||||
|
||||
// Created is the time the object was created. This field is read-only.
|
||||
@@ -1155,7 +1163,7 @@ var attrToFieldMap = map[string]string{
|
||||
"ContentEncoding": "contentEncoding",
|
||||
"ContentDisposition": "contentDisposition",
|
||||
"Size": "size",
|
||||
"MD5": "md5hash",
|
||||
"MD5": "md5Hash",
|
||||
"CRC32C": "crc32c",
|
||||
"MediaLink": "mediaLink",
|
||||
"Metadata": "metadata",
|
||||
@@ -1166,7 +1174,7 @@ var attrToFieldMap = map[string]string{
|
||||
"KMSKeyName": "kmsKeyName",
|
||||
"Created": "timeCreated",
|
||||
"Deleted": "timeDeleted",
|
||||
"Updated": "timeUpdated",
|
||||
"Updated": "updated",
|
||||
"Etag": "etag",
|
||||
}
|
||||
|
||||
|
||||
7
vendor/github.com/aws/aws-sdk-go/aws/config.go
generated
vendored
7
vendor/github.com/aws/aws-sdk-go/aws/config.go
generated
vendored
@@ -165,6 +165,13 @@ type Config struct {
|
||||
// in the ARN, when an ARN is provided as an argument to a bucket parameter.
|
||||
S3UseARNRegion *bool
|
||||
|
||||
// Set this to `true` to enable the SDK to unmarshal API response header maps to
|
||||
// normalized lower case map keys.
|
||||
//
|
||||
// For example S3's X-Amz-Meta prefixed header will be unmarshaled to lower case
|
||||
// Metadata member's map keys. The value of the header in the map is unaffected.
|
||||
LowerCaseHeaderMaps *bool
|
||||
|
||||
// Set this to `true` to disable the EC2Metadata client from overriding the
|
||||
// default http.Client's Timeout. This is helpful if you do not want the
|
||||
// EC2Metadata client to create a new http.Client. This options is only
|
||||
|
||||
2
vendor/github.com/aws/aws-sdk-go/aws/corehandlers/handlers.go
generated
vendored
2
vendor/github.com/aws/aws-sdk-go/aws/corehandlers/handlers.go
generated
vendored
@@ -161,7 +161,7 @@ func handleSendError(r *request.Request, err error) {
|
||||
}
|
||||
// Catch all request errors, and let the default retrier determine
|
||||
// if the error is retryable.
|
||||
r.Error = awserr.New("RequestError", "send request failed", err)
|
||||
r.Error = awserr.New(request.ErrCodeRequestError, "send request failed", err)
|
||||
|
||||
// Override the error with a context canceled error, if that was canceled.
|
||||
ctx := r.Context()
|
||||
|
||||
2
vendor/github.com/aws/aws-sdk-go/aws/csm/reporter.go
generated
vendored
2
vendor/github.com/aws/aws-sdk-go/aws/csm/reporter.go
generated
vendored
@@ -89,7 +89,7 @@ func getMetricException(err awserr.Error) metricException {
|
||||
code := err.Code()
|
||||
|
||||
switch code {
|
||||
case "RequestError",
|
||||
case request.ErrCodeRequestError,
|
||||
request.ErrCodeSerialization,
|
||||
request.CanceledErrorCode:
|
||||
return sdkException{
|
||||
|
||||
4
vendor/github.com/aws/aws-sdk-go/aws/ec2metadata/service.go
generated
vendored
4
vendor/github.com/aws/aws-sdk-go/aws/ec2metadata/service.go
generated
vendored
@@ -80,8 +80,10 @@ func NewClient(cfg aws.Config, handlers request.Handlers, endpoint, signingRegio
|
||||
// use a shorter timeout than default because the metadata
|
||||
// service is local if it is running, and to fail faster
|
||||
// if not running on an ec2 instance.
|
||||
Timeout: 5 * time.Second,
|
||||
Timeout: 1 * time.Second,
|
||||
}
|
||||
// max number of retries on the client operation
|
||||
cfg.MaxRetries = aws.Int(2)
|
||||
}
|
||||
|
||||
svc := &EC2Metadata{
|
||||
|
||||
2
vendor/github.com/aws/aws-sdk-go/aws/ec2metadata/token_provider.go
generated
vendored
2
vendor/github.com/aws/aws-sdk-go/aws/ec2metadata/token_provider.go
generated
vendored
@@ -62,7 +62,7 @@ func (t *tokenProvider) fetchTokenHandler(r *request.Request) {
|
||||
|
||||
// Check if request timed out while waiting for response
|
||||
if e, ok := requestFailureError.OrigErr().(awserr.Error); ok {
|
||||
if e.Code() == "RequestError" {
|
||||
if e.Code() == request.ErrCodeRequestError {
|
||||
atomic.StoreUint32(&t.disabled, 1)
|
||||
}
|
||||
}
|
||||
|
||||
19
vendor/github.com/aws/aws-sdk-go/aws/endpoints/defaults.go
generated
vendored
19
vendor/github.com/aws/aws-sdk-go/aws/endpoints/defaults.go
generated
vendored
@@ -2839,11 +2839,18 @@ var awsPartition = partition{
|
||||
"outposts": service{
|
||||
|
||||
Endpoints: endpoints{
|
||||
"ap-east-1": endpoint{},
|
||||
"ap-northeast-1": endpoint{},
|
||||
"ap-northeast-2": endpoint{},
|
||||
"ap-southeast-1": endpoint{},
|
||||
"ap-southeast-2": endpoint{},
|
||||
"ca-central-1": endpoint{},
|
||||
"eu-central-1": endpoint{},
|
||||
"eu-north-1": endpoint{},
|
||||
"eu-west-1": endpoint{},
|
||||
"eu-west-2": endpoint{},
|
||||
"eu-west-3": endpoint{},
|
||||
"me-south-1": endpoint{},
|
||||
"us-east-1": endpoint{},
|
||||
"us-east-2": endpoint{},
|
||||
"us-west-1": endpoint{},
|
||||
@@ -2996,6 +3003,7 @@ var awsPartition = partition{
|
||||
"ram": service{
|
||||
|
||||
Endpoints: endpoints{
|
||||
"ap-east-1": endpoint{},
|
||||
"ap-northeast-1": endpoint{},
|
||||
"ap-northeast-2": endpoint{},
|
||||
"ap-south-1": endpoint{},
|
||||
@@ -3007,6 +3015,7 @@ var awsPartition = partition{
|
||||
"eu-west-1": endpoint{},
|
||||
"eu-west-2": endpoint{},
|
||||
"eu-west-3": endpoint{},
|
||||
"me-south-1": endpoint{},
|
||||
"sa-east-1": endpoint{},
|
||||
"us-east-1": endpoint{},
|
||||
"us-east-2": endpoint{},
|
||||
@@ -3162,6 +3171,7 @@ var awsPartition = partition{
|
||||
Protocols: []string{"https"},
|
||||
},
|
||||
Endpoints: endpoints{
|
||||
"ap-east-1": endpoint{},
|
||||
"ap-northeast-1": endpoint{},
|
||||
"ap-northeast-2": endpoint{},
|
||||
"ap-south-1": endpoint{},
|
||||
@@ -4561,6 +4571,13 @@ var awscnPartition = partition{
|
||||
"cn-north-1": endpoint{},
|
||||
},
|
||||
},
|
||||
"health": service{
|
||||
|
||||
Endpoints: endpoints{
|
||||
"cn-north-1": endpoint{},
|
||||
"cn-northwest-1": endpoint{},
|
||||
},
|
||||
},
|
||||
"iam": service{
|
||||
PartitionEndpoint: "aws-cn-global",
|
||||
IsRegionalized: boxedFalse,
|
||||
@@ -5715,7 +5732,6 @@ var awsisoPartition = partition{
|
||||
},
|
||||
"application-autoscaling": service{
|
||||
Defaults: endpoint{
|
||||
Hostname: "autoscaling.us-iso-east-1.c2s.ic.gov",
|
||||
Protocols: []string{"http", "https"},
|
||||
},
|
||||
Endpoints: endpoints{
|
||||
@@ -6044,7 +6060,6 @@ var awsisobPartition = partition{
|
||||
Services: services{
|
||||
"application-autoscaling": service{
|
||||
Defaults: endpoint{
|
||||
Hostname: "autoscaling.us-isob-east-1.sc2s.sgov.gov",
|
||||
Protocols: []string{"http", "https"},
|
||||
},
|
||||
Endpoints: endpoints{
|
||||
|
||||
21
vendor/github.com/aws/aws-sdk-go/aws/request/handlers.go
generated
vendored
21
vendor/github.com/aws/aws-sdk-go/aws/request/handlers.go
generated
vendored
@@ -10,6 +10,7 @@ import (
|
||||
type Handlers struct {
|
||||
Validate HandlerList
|
||||
Build HandlerList
|
||||
BuildStream HandlerList
|
||||
Sign HandlerList
|
||||
Send HandlerList
|
||||
ValidateResponse HandlerList
|
||||
@@ -28,6 +29,7 @@ func (h *Handlers) Copy() Handlers {
|
||||
return Handlers{
|
||||
Validate: h.Validate.copy(),
|
||||
Build: h.Build.copy(),
|
||||
BuildStream: h.BuildStream.copy(),
|
||||
Sign: h.Sign.copy(),
|
||||
Send: h.Send.copy(),
|
||||
ValidateResponse: h.ValidateResponse.copy(),
|
||||
@@ -46,6 +48,7 @@ func (h *Handlers) Copy() Handlers {
|
||||
func (h *Handlers) Clear() {
|
||||
h.Validate.Clear()
|
||||
h.Build.Clear()
|
||||
h.BuildStream.Clear()
|
||||
h.Send.Clear()
|
||||
h.Sign.Clear()
|
||||
h.Unmarshal.Clear()
|
||||
@@ -67,6 +70,9 @@ func (h *Handlers) IsEmpty() bool {
|
||||
if h.Build.Len() != 0 {
|
||||
return false
|
||||
}
|
||||
if h.BuildStream.Len() != 0 {
|
||||
return false
|
||||
}
|
||||
if h.Send.Len() != 0 {
|
||||
return false
|
||||
}
|
||||
@@ -320,3 +326,18 @@ func MakeAddToUserAgentFreeFormHandler(s string) func(*Request) {
|
||||
AddToUserAgent(r, s)
|
||||
}
|
||||
}
|
||||
|
||||
// WithSetRequestHeaders updates the operation request's HTTP header to contain
|
||||
// the header key value pairs provided. If the header key already exists in the
|
||||
// request's HTTP header set, the existing value(s) will be replaced.
|
||||
func WithSetRequestHeaders(h map[string]string) Option {
|
||||
return withRequestHeader(h).SetRequestHeaders
|
||||
}
|
||||
|
||||
type withRequestHeader map[string]string
|
||||
|
||||
func (h withRequestHeader) SetRequestHeaders(r *Request) {
|
||||
for k, v := range h {
|
||||
r.HTTPRequest.Header[k] = []string{v}
|
||||
}
|
||||
}
|
||||
|
||||
16
vendor/github.com/aws/aws-sdk-go/aws/request/request.go
generated
vendored
16
vendor/github.com/aws/aws-sdk-go/aws/request/request.go
generated
vendored
@@ -36,6 +36,10 @@ const (
|
||||
// API request that was canceled. Requests given a aws.Context may
|
||||
// return this error when canceled.
|
||||
CanceledErrorCode = "RequestCanceled"
|
||||
|
||||
// ErrCodeRequestError is an error preventing the SDK from continuing to
|
||||
// process the request.
|
||||
ErrCodeRequestError = "RequestError"
|
||||
)
|
||||
|
||||
// A Request is the service request to be made.
|
||||
@@ -51,6 +55,7 @@ type Request struct {
|
||||
HTTPRequest *http.Request
|
||||
HTTPResponse *http.Response
|
||||
Body io.ReadSeeker
|
||||
streamingBody io.ReadCloser
|
||||
BodyStart int64 // offset from beginning of Body that the request body starts
|
||||
Params interface{}
|
||||
Error error
|
||||
@@ -295,6 +300,13 @@ func (r *Request) SetReaderBody(reader io.ReadSeeker) {
|
||||
r.ResetBody()
|
||||
}
|
||||
|
||||
// SetStreamingBody set the reader to be used for the request that will stream
|
||||
// bytes to the server. Request's Body must not be set to any reader.
|
||||
func (r *Request) SetStreamingBody(reader io.ReadCloser) {
|
||||
r.streamingBody = reader
|
||||
r.SetReaderBody(aws.ReadSeekCloser(reader))
|
||||
}
|
||||
|
||||
// Presign returns the request's signed URL. Error will be returned
|
||||
// if the signing fails. The expire parameter is only used for presigned Amazon
|
||||
// S3 API requests. All other AWS services will use a fixed expiration
|
||||
@@ -419,6 +431,10 @@ func (r *Request) Sign() error {
|
||||
}
|
||||
|
||||
func (r *Request) getNextRequestBody() (body io.ReadCloser, err error) {
|
||||
if r.streamingBody != nil {
|
||||
return r.streamingBody, nil
|
||||
}
|
||||
|
||||
if r.safeBody != nil {
|
||||
r.safeBody.Close()
|
||||
}
|
||||
|
||||
4
vendor/github.com/aws/aws-sdk-go/aws/request/retryer.go
generated
vendored
4
vendor/github.com/aws/aws-sdk-go/aws/request/retryer.go
generated
vendored
@@ -75,7 +75,7 @@ func (d noOpRetryer) RetryRules(_ *Request) time.Duration {
|
||||
// retryableCodes is a collection of service response codes which are retry-able
|
||||
// without any further action.
|
||||
var retryableCodes = map[string]struct{}{
|
||||
"RequestError": {},
|
||||
ErrCodeRequestError: {},
|
||||
"RequestTimeout": {},
|
||||
ErrCodeResponseTimeout: {},
|
||||
"RequestTimeoutException": {}, // Glacier's flavor of RequestTimeout
|
||||
@@ -178,7 +178,7 @@ func shouldRetryError(origErr error) bool {
|
||||
var shouldRetry bool
|
||||
if origErr != nil {
|
||||
shouldRetry = shouldRetryError(origErr)
|
||||
if err.Code() == "RequestError" && !shouldRetry {
|
||||
if err.Code() == ErrCodeRequestError && !shouldRetry {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
14
vendor/github.com/aws/aws-sdk-go/aws/session/session.go
generated
vendored
14
vendor/github.com/aws/aws-sdk-go/aws/session/session.go
generated
vendored
@@ -642,10 +642,16 @@ func (s *Session) ClientConfig(service string, cfgs ...*aws.Config) client.Confi
|
||||
|
||||
region := aws.StringValue(s.Config.Region)
|
||||
resolved, err := s.resolveEndpoint(service, region, s.Config)
|
||||
if err != nil && s.Config.Logger != nil {
|
||||
s.Config.Logger.Log(fmt.Sprintf(
|
||||
"ERROR: unable to resolve endpoint for service %q, region %q, err: %v",
|
||||
service, region, err))
|
||||
if err != nil {
|
||||
s.Handlers.Validate.PushBack(func(r *request.Request) {
|
||||
if len(r.ClientInfo.Endpoint) != 0 {
|
||||
// Error occurred while resolving endpoint, but the request
|
||||
// being invoked has had an endpoint specified after the client
|
||||
// was created.
|
||||
return
|
||||
}
|
||||
r.Error = err
|
||||
})
|
||||
}
|
||||
|
||||
return client.Config{
|
||||
|
||||
5
vendor/github.com/aws/aws-sdk-go/aws/signer/v4/header_rules.go
generated
vendored
5
vendor/github.com/aws/aws-sdk-go/aws/signer/v4/header_rules.go
generated
vendored
@@ -1,8 +1,7 @@
|
||||
package v4
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strings"
|
||||
"github.com/aws/aws-sdk-go/internal/strings"
|
||||
)
|
||||
|
||||
// validator houses a set of rule needed for validation of a
|
||||
@@ -61,7 +60,7 @@ type patterns []string
|
||||
// been found
|
||||
func (p patterns) IsValid(value string) bool {
|
||||
for _, pattern := range p {
|
||||
if strings.HasPrefix(http.CanonicalHeaderKey(value), pattern) {
|
||||
if strings.HasPrefixFold(value, pattern) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
63
vendor/github.com/aws/aws-sdk-go/aws/signer/v4/stream.go
generated
vendored
Normal file
63
vendor/github.com/aws/aws-sdk-go/aws/signer/v4/stream.go
generated
vendored
Normal file
@@ -0,0 +1,63 @@
|
||||
package v4
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws/credentials"
|
||||
)
|
||||
|
||||
type credentialValueProvider interface {
|
||||
Get() (credentials.Value, error)
|
||||
}
|
||||
|
||||
// StreamSigner implements signing of event stream encoded payloads
|
||||
type StreamSigner struct {
|
||||
region string
|
||||
service string
|
||||
|
||||
credentials credentialValueProvider
|
||||
|
||||
prevSig []byte
|
||||
}
|
||||
|
||||
// NewStreamSigner creates a SigV4 signer used to sign Event Stream encoded messages
|
||||
func NewStreamSigner(region, service string, seedSignature []byte, credentials *credentials.Credentials) *StreamSigner {
|
||||
return &StreamSigner{
|
||||
region: region,
|
||||
service: service,
|
||||
credentials: credentials,
|
||||
prevSig: seedSignature,
|
||||
}
|
||||
}
|
||||
|
||||
// GetSignature takes an event stream encoded headers and payload and returns a signature
|
||||
func (s *StreamSigner) GetSignature(headers, payload []byte, date time.Time) ([]byte, error) {
|
||||
credValue, err := s.credentials.Get()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
sigKey := deriveSigningKey(s.region, s.service, credValue.SecretAccessKey, date)
|
||||
|
||||
keyPath := buildSigningScope(s.region, s.service, date)
|
||||
|
||||
stringToSign := buildEventStreamStringToSign(headers, payload, s.prevSig, keyPath, date)
|
||||
|
||||
signature := hmacSHA256(sigKey, []byte(stringToSign))
|
||||
s.prevSig = signature
|
||||
|
||||
return signature, nil
|
||||
}
|
||||
|
||||
func buildEventStreamStringToSign(headers, payload, prevSig []byte, scope string, date time.Time) string {
|
||||
return strings.Join([]string{
|
||||
"AWS4-HMAC-SHA256-PAYLOAD",
|
||||
formatTime(date),
|
||||
scope,
|
||||
hex.EncodeToString(prevSig),
|
||||
hex.EncodeToString(hashSHA256(headers)),
|
||||
hex.EncodeToString(hashSHA256(payload)),
|
||||
}, "\n")
|
||||
}
|
||||
108
vendor/github.com/aws/aws-sdk-go/aws/signer/v4/v4.go
generated
vendored
108
vendor/github.com/aws/aws-sdk-go/aws/signer/v4/v4.go
generated
vendored
@@ -76,9 +76,14 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
authorizationHeader = "Authorization"
|
||||
authHeaderSignatureElem = "Signature="
|
||||
signatureQueryKey = "X-Amz-Signature"
|
||||
|
||||
authHeaderPrefix = "AWS4-HMAC-SHA256"
|
||||
timeFormat = "20060102T150405Z"
|
||||
shortTimeFormat = "20060102"
|
||||
awsV4Request = "aws4_request"
|
||||
|
||||
// emptyStringSHA256 is a SHA256 of an empty string
|
||||
emptyStringSHA256 = `e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855`
|
||||
@@ -87,9 +92,9 @@ const (
|
||||
var ignoredHeaders = rules{
|
||||
blacklist{
|
||||
mapRule{
|
||||
"Authorization": struct{}{},
|
||||
"User-Agent": struct{}{},
|
||||
"X-Amzn-Trace-Id": struct{}{},
|
||||
authorizationHeader: struct{}{},
|
||||
"User-Agent": struct{}{},
|
||||
"X-Amzn-Trace-Id": struct{}{},
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -229,11 +234,9 @@ type signingCtx struct {
|
||||
|
||||
DisableURIPathEscaping bool
|
||||
|
||||
credValues credentials.Value
|
||||
isPresign bool
|
||||
formattedTime string
|
||||
formattedShortTime string
|
||||
unsignedPayload bool
|
||||
credValues credentials.Value
|
||||
isPresign bool
|
||||
unsignedPayload bool
|
||||
|
||||
bodyDigest string
|
||||
signedHeaders string
|
||||
@@ -532,39 +535,56 @@ func (ctx *signingCtx) build(disableHeaderHoisting bool) error {
|
||||
ctx.buildSignature() // depends on string to sign
|
||||
|
||||
if ctx.isPresign {
|
||||
ctx.Request.URL.RawQuery += "&X-Amz-Signature=" + ctx.signature
|
||||
ctx.Request.URL.RawQuery += "&" + signatureQueryKey + "=" + ctx.signature
|
||||
} else {
|
||||
parts := []string{
|
||||
authHeaderPrefix + " Credential=" + ctx.credValues.AccessKeyID + "/" + ctx.credentialString,
|
||||
"SignedHeaders=" + ctx.signedHeaders,
|
||||
"Signature=" + ctx.signature,
|
||||
authHeaderSignatureElem + ctx.signature,
|
||||
}
|
||||
ctx.Request.Header.Set("Authorization", strings.Join(parts, ", "))
|
||||
ctx.Request.Header.Set(authorizationHeader, strings.Join(parts, ", "))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ctx *signingCtx) buildTime() {
|
||||
ctx.formattedTime = ctx.Time.UTC().Format(timeFormat)
|
||||
ctx.formattedShortTime = ctx.Time.UTC().Format(shortTimeFormat)
|
||||
// GetSignedRequestSignature attempts to extract the signature of the request.
|
||||
// Returning an error if the request is unsigned, or unable to extract the
|
||||
// signature.
|
||||
func GetSignedRequestSignature(r *http.Request) ([]byte, error) {
|
||||
|
||||
if auth := r.Header.Get(authorizationHeader); len(auth) != 0 {
|
||||
ps := strings.Split(auth, ", ")
|
||||
for _, p := range ps {
|
||||
if idx := strings.Index(p, authHeaderSignatureElem); idx >= 0 {
|
||||
sig := p[len(authHeaderSignatureElem):]
|
||||
if len(sig) == 0 {
|
||||
return nil, fmt.Errorf("invalid request signature authorization header")
|
||||
}
|
||||
return hex.DecodeString(sig)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if sig := r.URL.Query().Get("X-Amz-Signature"); len(sig) != 0 {
|
||||
return hex.DecodeString(sig)
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("request not signed")
|
||||
}
|
||||
|
||||
func (ctx *signingCtx) buildTime() {
|
||||
if ctx.isPresign {
|
||||
duration := int64(ctx.ExpireTime / time.Second)
|
||||
ctx.Query.Set("X-Amz-Date", ctx.formattedTime)
|
||||
ctx.Query.Set("X-Amz-Date", formatTime(ctx.Time))
|
||||
ctx.Query.Set("X-Amz-Expires", strconv.FormatInt(duration, 10))
|
||||
} else {
|
||||
ctx.Request.Header.Set("X-Amz-Date", ctx.formattedTime)
|
||||
ctx.Request.Header.Set("X-Amz-Date", formatTime(ctx.Time))
|
||||
}
|
||||
}
|
||||
|
||||
func (ctx *signingCtx) buildCredentialString() {
|
||||
ctx.credentialString = strings.Join([]string{
|
||||
ctx.formattedShortTime,
|
||||
ctx.Region,
|
||||
ctx.ServiceName,
|
||||
"aws4_request",
|
||||
}, "/")
|
||||
ctx.credentialString = buildSigningScope(ctx.Region, ctx.ServiceName, ctx.Time)
|
||||
|
||||
if ctx.isPresign {
|
||||
ctx.Query.Set("X-Amz-Credential", ctx.credValues.AccessKeyID+"/"+ctx.credentialString)
|
||||
@@ -588,8 +608,7 @@ func (ctx *signingCtx) buildCanonicalHeaders(r rule, header http.Header) {
|
||||
var headers []string
|
||||
headers = append(headers, "host")
|
||||
for k, v := range header {
|
||||
canonicalKey := http.CanonicalHeaderKey(k)
|
||||
if !r.IsValid(canonicalKey) {
|
||||
if !r.IsValid(k) {
|
||||
continue // ignored header
|
||||
}
|
||||
if ctx.SignedHeaderVals == nil {
|
||||
@@ -653,19 +672,15 @@ func (ctx *signingCtx) buildCanonicalString() {
|
||||
func (ctx *signingCtx) buildStringToSign() {
|
||||
ctx.stringToSign = strings.Join([]string{
|
||||
authHeaderPrefix,
|
||||
ctx.formattedTime,
|
||||
formatTime(ctx.Time),
|
||||
ctx.credentialString,
|
||||
hex.EncodeToString(makeSha256([]byte(ctx.canonicalString))),
|
||||
hex.EncodeToString(hashSHA256([]byte(ctx.canonicalString))),
|
||||
}, "\n")
|
||||
}
|
||||
|
||||
func (ctx *signingCtx) buildSignature() {
|
||||
secret := ctx.credValues.SecretAccessKey
|
||||
date := makeHmac([]byte("AWS4"+secret), []byte(ctx.formattedShortTime))
|
||||
region := makeHmac(date, []byte(ctx.Region))
|
||||
service := makeHmac(region, []byte(ctx.ServiceName))
|
||||
credentials := makeHmac(service, []byte("aws4_request"))
|
||||
signature := makeHmac(credentials, []byte(ctx.stringToSign))
|
||||
creds := deriveSigningKey(ctx.Region, ctx.ServiceName, ctx.credValues.SecretAccessKey, ctx.Time)
|
||||
signature := hmacSHA256(creds, []byte(ctx.stringToSign))
|
||||
ctx.signature = hex.EncodeToString(signature)
|
||||
}
|
||||
|
||||
@@ -726,13 +741,13 @@ func (ctx *signingCtx) removePresign() {
|
||||
ctx.Query.Del("X-Amz-SignedHeaders")
|
||||
}
|
||||
|
||||
func makeHmac(key []byte, data []byte) []byte {
|
||||
func hmacSHA256(key []byte, data []byte) []byte {
|
||||
hash := hmac.New(sha256.New, key)
|
||||
hash.Write(data)
|
||||
return hash.Sum(nil)
|
||||
}
|
||||
|
||||
func makeSha256(data []byte) []byte {
|
||||
func hashSHA256(data []byte) []byte {
|
||||
hash := sha256.New()
|
||||
hash.Write(data)
|
||||
return hash.Sum(nil)
|
||||
@@ -804,3 +819,28 @@ func stripExcessSpaces(vals []string) {
|
||||
vals[i] = string(buf[:m])
|
||||
}
|
||||
}
|
||||
|
||||
func buildSigningScope(region, service string, dt time.Time) string {
|
||||
return strings.Join([]string{
|
||||
formatShortTime(dt),
|
||||
region,
|
||||
service,
|
||||
awsV4Request,
|
||||
}, "/")
|
||||
}
|
||||
|
||||
func deriveSigningKey(region, service, secretKey string, dt time.Time) []byte {
|
||||
kDate := hmacSHA256([]byte("AWS4"+secretKey), []byte(formatShortTime(dt)))
|
||||
kRegion := hmacSHA256(kDate, []byte(region))
|
||||
kService := hmacSHA256(kRegion, []byte(service))
|
||||
signingKey := hmacSHA256(kService, []byte(awsV4Request))
|
||||
return signingKey
|
||||
}
|
||||
|
||||
func formatShortTime(dt time.Time) string {
|
||||
return dt.UTC().Format(shortTimeFormat)
|
||||
}
|
||||
|
||||
func formatTime(dt time.Time) string {
|
||||
return dt.UTC().Format(timeFormat)
|
||||
}
|
||||
|
||||
34
vendor/github.com/aws/aws-sdk-go/aws/types.go
generated
vendored
34
vendor/github.com/aws/aws-sdk-go/aws/types.go
generated
vendored
@@ -2,6 +2,7 @@ package aws
|
||||
|
||||
import (
|
||||
"io"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/aws/aws-sdk-go/internal/sdkio"
|
||||
@@ -205,3 +206,36 @@ func (b *WriteAtBuffer) Bytes() []byte {
|
||||
defer b.m.Unlock()
|
||||
return b.buf
|
||||
}
|
||||
|
||||
// MultiCloser is a utility to close multiple io.Closers within a single
|
||||
// statement.
|
||||
type MultiCloser []io.Closer
|
||||
|
||||
// Close closes all of the io.Closers making up the MultiClosers. Any
|
||||
// errors that occur while closing will be returned in the order they
|
||||
// occur.
|
||||
func (m MultiCloser) Close() error {
|
||||
var errs errors
|
||||
for _, c := range m {
|
||||
err := c.Close()
|
||||
if err != nil {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
}
|
||||
if len(errs) != 0 {
|
||||
return errs
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type errors []error
|
||||
|
||||
func (es errors) Error() string {
|
||||
var parts []string
|
||||
for _, e := range es {
|
||||
parts = append(parts, e.Error())
|
||||
}
|
||||
|
||||
return strings.Join(parts, "\n")
|
||||
}
|
||||
|
||||
2
vendor/github.com/aws/aws-sdk-go/aws/version.go
generated
vendored
2
vendor/github.com/aws/aws-sdk-go/aws/version.go
generated
vendored
@@ -5,4 +5,4 @@ package aws
|
||||
const SDKName = "aws-sdk-go"
|
||||
|
||||
// SDKVersion is the version of this SDK
|
||||
const SDKVersion = "1.26.8"
|
||||
const SDKVersion = "1.28.3"
|
||||
|
||||
11
vendor/github.com/aws/aws-sdk-go/internal/strings/strings.go
generated
vendored
Normal file
11
vendor/github.com/aws/aws-sdk-go/internal/strings/strings.go
generated
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
package strings
|
||||
|
||||
import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
// HasPrefixFold tests whether the string s begins with prefix, interpreted as UTF-8 strings,
|
||||
// under Unicode case-folding.
|
||||
func HasPrefixFold(s, prefix string) bool {
|
||||
return len(s) >= len(prefix) && strings.EqualFold(s[0:len(prefix)], prefix)
|
||||
}
|
||||
2
vendor/github.com/aws/aws-sdk-go/private/protocol/eventstream/debug.go
generated
vendored
2
vendor/github.com/aws/aws-sdk-go/private/protocol/eventstream/debug.go
generated
vendored
@@ -101,7 +101,7 @@ func (hs *decodedHeaders) UnmarshalJSON(b []byte) error {
|
||||
}
|
||||
headers.Set(h.Name, value)
|
||||
}
|
||||
(*hs) = decodedHeaders(headers)
|
||||
*hs = decodedHeaders(headers)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
33
vendor/github.com/aws/aws-sdk-go/private/protocol/eventstream/decode.go
generated
vendored
33
vendor/github.com/aws/aws-sdk-go/private/protocol/eventstream/decode.go
generated
vendored
@@ -21,10 +21,24 @@ type Decoder struct {
|
||||
|
||||
// NewDecoder initializes and returns a Decoder for decoding event
|
||||
// stream messages from the reader provided.
|
||||
func NewDecoder(r io.Reader) *Decoder {
|
||||
return &Decoder{
|
||||
func NewDecoder(r io.Reader, opts ...func(*Decoder)) *Decoder {
|
||||
d := &Decoder{
|
||||
r: r,
|
||||
}
|
||||
|
||||
for _, opt := range opts {
|
||||
opt(d)
|
||||
}
|
||||
|
||||
return d
|
||||
}
|
||||
|
||||
// DecodeWithLogger adds a logger to be used by the decoder when decoding
|
||||
// stream events.
|
||||
func DecodeWithLogger(logger aws.Logger) func(*Decoder) {
|
||||
return func(d *Decoder) {
|
||||
d.logger = logger
|
||||
}
|
||||
}
|
||||
|
||||
// Decode attempts to decode a single message from the event stream reader.
|
||||
@@ -40,6 +54,15 @@ func (d *Decoder) Decode(payloadBuf []byte) (m Message, err error) {
|
||||
}()
|
||||
}
|
||||
|
||||
m, err = Decode(reader, payloadBuf)
|
||||
|
||||
return m, err
|
||||
}
|
||||
|
||||
// Decode attempts to decode a single message from the event stream reader.
|
||||
// Will return the event stream message, or error if Decode fails to read
|
||||
// the message from the reader.
|
||||
func Decode(reader io.Reader, payloadBuf []byte) (m Message, err error) {
|
||||
crc := crc32.New(crc32IEEETable)
|
||||
hashReader := io.TeeReader(reader, crc)
|
||||
|
||||
@@ -72,12 +95,6 @@ func (d *Decoder) Decode(payloadBuf []byte) (m Message, err error) {
|
||||
return m, nil
|
||||
}
|
||||
|
||||
// UseLogger specifies the Logger that that the decoder should use to log the
|
||||
// message decode to.
|
||||
func (d *Decoder) UseLogger(logger aws.Logger) {
|
||||
d.logger = logger
|
||||
}
|
||||
|
||||
func logMessageDecode(logger aws.Logger, msgBuf *bytes.Buffer, msg Message, decodeErr error) {
|
||||
w := bytes.NewBuffer(nil)
|
||||
defer func() { logger.Log(w.String()) }()
|
||||
|
||||
72
vendor/github.com/aws/aws-sdk-go/private/protocol/eventstream/encode.go
generated
vendored
72
vendor/github.com/aws/aws-sdk-go/private/protocol/eventstream/encode.go
generated
vendored
@@ -3,61 +3,107 @@ package eventstream
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"hash"
|
||||
"hash/crc32"
|
||||
"io"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
)
|
||||
|
||||
// Encoder provides EventStream message encoding.
|
||||
type Encoder struct {
|
||||
w io.Writer
|
||||
w io.Writer
|
||||
logger aws.Logger
|
||||
|
||||
headersBuf *bytes.Buffer
|
||||
}
|
||||
|
||||
// NewEncoder initializes and returns an Encoder to encode Event Stream
|
||||
// messages to an io.Writer.
|
||||
func NewEncoder(w io.Writer) *Encoder {
|
||||
return &Encoder{
|
||||
func NewEncoder(w io.Writer, opts ...func(*Encoder)) *Encoder {
|
||||
e := &Encoder{
|
||||
w: w,
|
||||
headersBuf: bytes.NewBuffer(nil),
|
||||
}
|
||||
|
||||
for _, opt := range opts {
|
||||
opt(e)
|
||||
}
|
||||
|
||||
return e
|
||||
}
|
||||
|
||||
// EncodeWithLogger adds a logger to be used by the encode when decoding
|
||||
// stream events.
|
||||
func EncodeWithLogger(logger aws.Logger) func(*Encoder) {
|
||||
return func(d *Encoder) {
|
||||
d.logger = logger
|
||||
}
|
||||
}
|
||||
|
||||
// Encode encodes a single EventStream message to the io.Writer the Encoder
|
||||
// was created with. An error is returned if writing the message fails.
|
||||
func (e *Encoder) Encode(msg Message) error {
|
||||
func (e *Encoder) Encode(msg Message) (err error) {
|
||||
e.headersBuf.Reset()
|
||||
|
||||
err := encodeHeaders(e.headersBuf, msg.Headers)
|
||||
if err != nil {
|
||||
writer := e.w
|
||||
if e.logger != nil {
|
||||
encodeMsgBuf := bytes.NewBuffer(nil)
|
||||
writer = io.MultiWriter(writer, encodeMsgBuf)
|
||||
defer func() {
|
||||
logMessageEncode(e.logger, encodeMsgBuf, msg, err)
|
||||
}()
|
||||
}
|
||||
|
||||
if err = EncodeHeaders(e.headersBuf, msg.Headers); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
crc := crc32.New(crc32IEEETable)
|
||||
hashWriter := io.MultiWriter(e.w, crc)
|
||||
hashWriter := io.MultiWriter(writer, crc)
|
||||
|
||||
headersLen := uint32(e.headersBuf.Len())
|
||||
payloadLen := uint32(len(msg.Payload))
|
||||
|
||||
if err := encodePrelude(hashWriter, crc, headersLen, payloadLen); err != nil {
|
||||
if err = encodePrelude(hashWriter, crc, headersLen, payloadLen); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if headersLen > 0 {
|
||||
if _, err := io.Copy(hashWriter, e.headersBuf); err != nil {
|
||||
if _, err = io.Copy(hashWriter, e.headersBuf); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if payloadLen > 0 {
|
||||
if _, err := hashWriter.Write(msg.Payload); err != nil {
|
||||
if _, err = hashWriter.Write(msg.Payload); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
msgCRC := crc.Sum32()
|
||||
return binary.Write(e.w, binary.BigEndian, msgCRC)
|
||||
return binary.Write(writer, binary.BigEndian, msgCRC)
|
||||
}
|
||||
|
||||
func logMessageEncode(logger aws.Logger, msgBuf *bytes.Buffer, msg Message, encodeErr error) {
|
||||
w := bytes.NewBuffer(nil)
|
||||
defer func() { logger.Log(w.String()) }()
|
||||
|
||||
fmt.Fprintf(w, "Message to encode:\n")
|
||||
encoder := json.NewEncoder(w)
|
||||
if err := encoder.Encode(msg); err != nil {
|
||||
fmt.Fprintf(w, "Failed to get encoded message, %v\n", err)
|
||||
}
|
||||
|
||||
if encodeErr != nil {
|
||||
fmt.Fprintf(w, "Encode error: %v\n", encodeErr)
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Fprintf(w, "Raw message:\n%s\n", hex.Dump(msgBuf.Bytes()))
|
||||
}
|
||||
|
||||
func encodePrelude(w io.Writer, crc hash.Hash32, headersLen, payloadLen uint32) error {
|
||||
@@ -86,7 +132,9 @@ func encodePrelude(w io.Writer, crc hash.Hash32, headersLen, payloadLen uint32)
|
||||
return nil
|
||||
}
|
||||
|
||||
func encodeHeaders(w io.Writer, headers Headers) error {
|
||||
// EncodeHeaders writes the header values to the writer encoded in the event
|
||||
// stream format. Returns an error if a header fails to encode.
|
||||
func EncodeHeaders(w io.Writer, headers Headers) error {
|
||||
for _, h := range headers {
|
||||
hn := headerName{
|
||||
Len: uint8(len(h.Name)),
|
||||
|
||||
55
vendor/github.com/aws/aws-sdk-go/private/protocol/eventstream/eventstreamapi/error.go
generated
vendored
55
vendor/github.com/aws/aws-sdk-go/private/protocol/eventstream/eventstreamapi/error.go
generated
vendored
@@ -1,6 +1,9 @@
|
||||
package eventstreamapi
|
||||
|
||||
import "fmt"
|
||||
import (
|
||||
"fmt"
|
||||
"sync"
|
||||
)
|
||||
|
||||
type messageError struct {
|
||||
code string
|
||||
@@ -22,3 +25,53 @@ func (e messageError) Error() string {
|
||||
func (e messageError) OrigErr() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// OnceError wraps the behavior of recording an error
|
||||
// once and signal on a channel when this has occurred.
|
||||
// Signaling is done by closing of the channel.
|
||||
//
|
||||
// Type is safe for concurrent usage.
|
||||
type OnceError struct {
|
||||
mu sync.RWMutex
|
||||
err error
|
||||
ch chan struct{}
|
||||
}
|
||||
|
||||
// NewOnceError return a new OnceError
|
||||
func NewOnceError() *OnceError {
|
||||
return &OnceError{
|
||||
ch: make(chan struct{}, 1),
|
||||
}
|
||||
}
|
||||
|
||||
// Err acquires a read-lock and returns an
|
||||
// error if one has been set.
|
||||
func (e *OnceError) Err() error {
|
||||
e.mu.RLock()
|
||||
err := e.err
|
||||
e.mu.RUnlock()
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// SetError acquires a write-lock and will set
|
||||
// the underlying error value if one has not been set.
|
||||
func (e *OnceError) SetError(err error) {
|
||||
if err == nil {
|
||||
return
|
||||
}
|
||||
|
||||
e.mu.Lock()
|
||||
if e.err == nil {
|
||||
e.err = err
|
||||
close(e.ch)
|
||||
}
|
||||
e.mu.Unlock()
|
||||
}
|
||||
|
||||
// ErrorSet returns a channel that will be used to signal
|
||||
// that an error has been set. This channel will be closed
|
||||
// when the error value has been set for OnceError.
|
||||
func (e *OnceError) ErrorSet() <-chan struct{} {
|
||||
return e.ch
|
||||
}
|
||||
|
||||
@@ -2,9 +2,7 @@ package eventstreamapi
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/private/protocol"
|
||||
"github.com/aws/aws-sdk-go/private/protocol/eventstream"
|
||||
)
|
||||
@@ -15,27 +13,8 @@ type Unmarshaler interface {
|
||||
UnmarshalEvent(protocol.PayloadUnmarshaler, eventstream.Message) error
|
||||
}
|
||||
|
||||
// EventStream headers with specific meaning to async API functionality.
|
||||
const (
|
||||
MessageTypeHeader = `:message-type` // Identifies type of message.
|
||||
EventMessageType = `event`
|
||||
ErrorMessageType = `error`
|
||||
ExceptionMessageType = `exception`
|
||||
|
||||
// Message Events
|
||||
EventTypeHeader = `:event-type` // Identifies message event type e.g. "Stats".
|
||||
|
||||
// Message Error
|
||||
ErrorCodeHeader = `:error-code`
|
||||
ErrorMessageHeader = `:error-message`
|
||||
|
||||
// Message Exception
|
||||
ExceptionTypeHeader = `:exception-type`
|
||||
)
|
||||
|
||||
// EventReader provides reading from the EventStream of an reader.
|
||||
type EventReader struct {
|
||||
reader io.ReadCloser
|
||||
decoder *eventstream.Decoder
|
||||
|
||||
unmarshalerForEventType func(string) (Unmarshaler, error)
|
||||
@@ -47,27 +26,18 @@ type EventReader struct {
|
||||
// NewEventReader returns a EventReader built from the reader and unmarshaler
|
||||
// provided. Use ReadStream method to start reading from the EventStream.
|
||||
func NewEventReader(
|
||||
reader io.ReadCloser,
|
||||
decoder *eventstream.Decoder,
|
||||
payloadUnmarshaler protocol.PayloadUnmarshaler,
|
||||
unmarshalerForEventType func(string) (Unmarshaler, error),
|
||||
) *EventReader {
|
||||
return &EventReader{
|
||||
reader: reader,
|
||||
decoder: eventstream.NewDecoder(reader),
|
||||
decoder: decoder,
|
||||
payloadUnmarshaler: payloadUnmarshaler,
|
||||
unmarshalerForEventType: unmarshalerForEventType,
|
||||
payloadBuf: make([]byte, 10*1024),
|
||||
}
|
||||
}
|
||||
|
||||
// UseLogger instructs the EventReader to use the logger and log level
|
||||
// specified.
|
||||
func (r *EventReader) UseLogger(logger aws.Logger, logLevel aws.LogLevelType) {
|
||||
if logger != nil && logLevel.Matches(aws.LogDebugWithEventStreamBody) {
|
||||
r.decoder.UseLogger(logger)
|
||||
}
|
||||
}
|
||||
|
||||
// ReadEvent attempts to read a message from the EventStream and return the
|
||||
// unmarshaled event value that the message is for.
|
||||
//
|
||||
@@ -95,8 +65,7 @@ func (r *EventReader) ReadEvent() (event interface{}, err error) {
|
||||
case EventMessageType:
|
||||
return r.unmarshalEventMessage(msg)
|
||||
case ExceptionMessageType:
|
||||
err = r.unmarshalEventException(msg)
|
||||
return nil, err
|
||||
return nil, r.unmarshalEventException(msg)
|
||||
case ErrorMessageType:
|
||||
return nil, r.unmarshalErrorMessage(msg)
|
||||
default:
|
||||
@@ -174,11 +143,6 @@ func (r *EventReader) unmarshalErrorMessage(msg eventstream.Message) (err error)
|
||||
return msgErr
|
||||
}
|
||||
|
||||
// Close closes the EventReader's EventStream reader.
|
||||
func (r *EventReader) Close() error {
|
||||
return r.reader.Close()
|
||||
}
|
||||
|
||||
// GetHeaderString returns the value of the header as a string. If the header
|
||||
// is not set or the value is not a string an error will be returned.
|
||||
func GetHeaderString(msg eventstream.Message, headerName string) (string, error) {
|
||||
23
vendor/github.com/aws/aws-sdk-go/private/protocol/eventstream/eventstreamapi/shared.go
generated
vendored
Normal file
23
vendor/github.com/aws/aws-sdk-go/private/protocol/eventstream/eventstreamapi/shared.go
generated
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
package eventstreamapi
|
||||
|
||||
// EventStream headers with specific meaning to async API functionality.
|
||||
const (
|
||||
ChunkSignatureHeader = `:chunk-signature` // chunk signature for message
|
||||
DateHeader = `:date` // Date header for signature
|
||||
|
||||
// Message header and values
|
||||
MessageTypeHeader = `:message-type` // Identifies type of message.
|
||||
EventMessageType = `event`
|
||||
ErrorMessageType = `error`
|
||||
ExceptionMessageType = `exception`
|
||||
|
||||
// Message Events
|
||||
EventTypeHeader = `:event-type` // Identifies message event type e.g. "Stats".
|
||||
|
||||
// Message Error
|
||||
ErrorCodeHeader = `:error-code`
|
||||
ErrorMessageHeader = `:error-message`
|
||||
|
||||
// Message Exception
|
||||
ExceptionTypeHeader = `:exception-type`
|
||||
)
|
||||
123
vendor/github.com/aws/aws-sdk-go/private/protocol/eventstream/eventstreamapi/signer.go
generated
vendored
Normal file
123
vendor/github.com/aws/aws-sdk-go/private/protocol/eventstream/eventstreamapi/signer.go
generated
vendored
Normal file
@@ -0,0 +1,123 @@
|
||||
package eventstreamapi
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/aws/aws-sdk-go/private/protocol/eventstream"
|
||||
)
|
||||
|
||||
var timeNow = time.Now
|
||||
|
||||
// StreamSigner defines an interface for the implementation of signing of event stream payloads
|
||||
type StreamSigner interface {
|
||||
GetSignature(headers, payload []byte, date time.Time) ([]byte, error)
|
||||
}
|
||||
|
||||
// SignEncoder envelopes event stream messages
|
||||
// into an event stream message payload with included
|
||||
// signature headers using the provided signer and encoder.
|
||||
type SignEncoder struct {
|
||||
signer StreamSigner
|
||||
encoder Encoder
|
||||
bufEncoder *BufferEncoder
|
||||
|
||||
closeErr error
|
||||
closed bool
|
||||
}
|
||||
|
||||
// NewSignEncoder returns a new SignEncoder using the provided stream signer and
|
||||
// event stream encoder.
|
||||
func NewSignEncoder(signer StreamSigner, encoder Encoder) *SignEncoder {
|
||||
// TODO: Need to pass down logging
|
||||
|
||||
return &SignEncoder{
|
||||
signer: signer,
|
||||
encoder: encoder,
|
||||
bufEncoder: NewBufferEncoder(),
|
||||
}
|
||||
}
|
||||
|
||||
// Close encodes a final event stream signing envelope with an empty event stream
|
||||
// payload. This final end-frame is used to mark the conclusion of the stream.
|
||||
func (s *SignEncoder) Close() error {
|
||||
if s.closed {
|
||||
return s.closeErr
|
||||
}
|
||||
|
||||
if err := s.encode([]byte{}); err != nil {
|
||||
if strings.Contains(err.Error(), "on closed pipe") {
|
||||
return nil
|
||||
}
|
||||
|
||||
s.closeErr = err
|
||||
s.closed = true
|
||||
return s.closeErr
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Encode takes the provided message and add envelopes the message
|
||||
// with the required signature.
|
||||
func (s *SignEncoder) Encode(msg eventstream.Message) error {
|
||||
payload, err := s.bufEncoder.Encode(msg)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return s.encode(payload)
|
||||
}
|
||||
|
||||
func (s SignEncoder) encode(payload []byte) error {
|
||||
date := timeNow()
|
||||
|
||||
var msg eventstream.Message
|
||||
msg.Headers.Set(DateHeader, eventstream.TimestampValue(date))
|
||||
msg.Payload = payload
|
||||
|
||||
var headers bytes.Buffer
|
||||
if err := eventstream.EncodeHeaders(&headers, msg.Headers); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
sig, err := s.signer.GetSignature(headers.Bytes(), msg.Payload, date)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
msg.Headers.Set(ChunkSignatureHeader, eventstream.BytesValue(sig))
|
||||
|
||||
return s.encoder.Encode(msg)
|
||||
}
|
||||
|
||||
// BufferEncoder is a utility that provides a buffered
|
||||
// event stream encoder
|
||||
type BufferEncoder struct {
|
||||
encoder Encoder
|
||||
buffer *bytes.Buffer
|
||||
}
|
||||
|
||||
// NewBufferEncoder returns a new BufferEncoder initialized
|
||||
// with a 1024 byte buffer.
|
||||
func NewBufferEncoder() *BufferEncoder {
|
||||
buf := bytes.NewBuffer(make([]byte, 1024))
|
||||
return &BufferEncoder{
|
||||
encoder: eventstream.NewEncoder(buf),
|
||||
buffer: buf,
|
||||
}
|
||||
}
|
||||
|
||||
// Encode returns the encoded message as a byte slice.
|
||||
// The returned byte slice will be modified on the next encode call
|
||||
// and should not be held onto.
|
||||
func (e *BufferEncoder) Encode(msg eventstream.Message) ([]byte, error) {
|
||||
e.buffer.Reset()
|
||||
|
||||
if err := e.encoder.Encode(msg); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return e.buffer.Bytes(), nil
|
||||
}
|
||||
129
vendor/github.com/aws/aws-sdk-go/private/protocol/eventstream/eventstreamapi/stream_writer.go
generated
vendored
Normal file
129
vendor/github.com/aws/aws-sdk-go/private/protocol/eventstream/eventstreamapi/stream_writer.go
generated
vendored
Normal file
@@ -0,0 +1,129 @@
|
||||
package eventstreamapi
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"sync"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
)
|
||||
|
||||
// StreamWriter provides concurrent safe writing to an event stream.
|
||||
type StreamWriter struct {
|
||||
eventWriter *EventWriter
|
||||
stream chan eventWriteAsyncReport
|
||||
|
||||
done chan struct{}
|
||||
closeOnce sync.Once
|
||||
err *OnceError
|
||||
|
||||
streamCloser io.Closer
|
||||
}
|
||||
|
||||
// NewStreamWriter returns a StreamWriter for the event writer, and stream
|
||||
// closer provided.
|
||||
func NewStreamWriter(eventWriter *EventWriter, streamCloser io.Closer) *StreamWriter {
|
||||
w := &StreamWriter{
|
||||
eventWriter: eventWriter,
|
||||
streamCloser: streamCloser,
|
||||
stream: make(chan eventWriteAsyncReport),
|
||||
done: make(chan struct{}),
|
||||
err: NewOnceError(),
|
||||
}
|
||||
go w.writeStream()
|
||||
|
||||
return w
|
||||
}
|
||||
|
||||
// Close terminates the writers ability to write new events to the stream. Any
|
||||
// future call to Send will fail with an error.
|
||||
func (w *StreamWriter) Close() error {
|
||||
w.closeOnce.Do(w.safeClose)
|
||||
return w.Err()
|
||||
}
|
||||
|
||||
func (w *StreamWriter) safeClose() {
|
||||
close(w.done)
|
||||
}
|
||||
|
||||
// ErrorSet returns a channel which will be closed
|
||||
// if an error occurs.
|
||||
func (w *StreamWriter) ErrorSet() <-chan struct{} {
|
||||
return w.err.ErrorSet()
|
||||
}
|
||||
|
||||
// Err returns any error that occurred while attempting to write an event to the
|
||||
// stream.
|
||||
func (w *StreamWriter) Err() error {
|
||||
return w.err.Err()
|
||||
}
|
||||
|
||||
// Send writes a single event to the stream returning an error if the write
|
||||
// failed.
|
||||
//
|
||||
// Send may be called concurrently. Events will be written to the stream
|
||||
// safely.
|
||||
func (w *StreamWriter) Send(ctx aws.Context, event Marshaler) error {
|
||||
if err := w.Err(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
resultCh := make(chan error)
|
||||
wrapped := eventWriteAsyncReport{
|
||||
Event: event,
|
||||
Result: resultCh,
|
||||
}
|
||||
|
||||
select {
|
||||
case w.stream <- wrapped:
|
||||
case <-ctx.Done():
|
||||
return ctx.Err()
|
||||
case <-w.done:
|
||||
return fmt.Errorf("stream closed, unable to send event")
|
||||
}
|
||||
|
||||
select {
|
||||
case err := <-resultCh:
|
||||
return err
|
||||
case <-ctx.Done():
|
||||
return ctx.Err()
|
||||
case <-w.done:
|
||||
return fmt.Errorf("stream closed, unable to send event")
|
||||
}
|
||||
}
|
||||
|
||||
func (w *StreamWriter) writeStream() {
|
||||
defer w.Close()
|
||||
|
||||
for {
|
||||
select {
|
||||
case wrapper := <-w.stream:
|
||||
err := w.eventWriter.WriteEvent(wrapper.Event)
|
||||
wrapper.ReportResult(w.done, err)
|
||||
if err != nil {
|
||||
w.err.SetError(err)
|
||||
return
|
||||
}
|
||||
|
||||
case <-w.done:
|
||||
if err := w.streamCloser.Close(); err != nil {
|
||||
w.err.SetError(err)
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type eventWriteAsyncReport struct {
|
||||
Event Marshaler
|
||||
Result chan<- error
|
||||
}
|
||||
|
||||
func (e eventWriteAsyncReport) ReportResult(cancel <-chan struct{}, err error) bool {
|
||||
select {
|
||||
case e.Result <- err:
|
||||
return true
|
||||
case <-cancel:
|
||||
return false
|
||||
}
|
||||
}
|
||||
109
vendor/github.com/aws/aws-sdk-go/private/protocol/eventstream/eventstreamapi/writer.go
generated
vendored
Normal file
109
vendor/github.com/aws/aws-sdk-go/private/protocol/eventstream/eventstreamapi/writer.go
generated
vendored
Normal file
@@ -0,0 +1,109 @@
|
||||
package eventstreamapi
|
||||
|
||||
import (
|
||||
"github.com/aws/aws-sdk-go/private/protocol"
|
||||
"github.com/aws/aws-sdk-go/private/protocol/eventstream"
|
||||
)
|
||||
|
||||
// Marshaler provides a marshaling interface for event types to event stream
|
||||
// messages.
|
||||
type Marshaler interface {
|
||||
MarshalEvent(protocol.PayloadMarshaler) (eventstream.Message, error)
|
||||
}
|
||||
|
||||
// Encoder is an stream encoder that will encode an event stream message for
|
||||
// the transport.
|
||||
type Encoder interface {
|
||||
Encode(eventstream.Message) error
|
||||
}
|
||||
|
||||
// EventWriter provides a wrapper around the underlying event stream encoder
|
||||
// for an io.WriteCloser.
|
||||
type EventWriter struct {
|
||||
encoder Encoder
|
||||
payloadMarshaler protocol.PayloadMarshaler
|
||||
eventTypeFor func(Marshaler) (string, error)
|
||||
}
|
||||
|
||||
// NewEventWriter returns a new event stream writer, that will write to the
|
||||
// writer provided. Use the WriteEvent method to write an event to the stream.
|
||||
func NewEventWriter(encoder Encoder, pm protocol.PayloadMarshaler, eventTypeFor func(Marshaler) (string, error),
|
||||
) *EventWriter {
|
||||
return &EventWriter{
|
||||
encoder: encoder,
|
||||
payloadMarshaler: pm,
|
||||
eventTypeFor: eventTypeFor,
|
||||
}
|
||||
}
|
||||
|
||||
// WriteEvent writes an event to the stream. Returns an error if the event
|
||||
// fails to marshal into a message, or writing to the underlying writer fails.
|
||||
func (w *EventWriter) WriteEvent(event Marshaler) error {
|
||||
msg, err := w.marshal(event)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return w.encoder.Encode(msg)
|
||||
}
|
||||
|
||||
func (w *EventWriter) marshal(event Marshaler) (eventstream.Message, error) {
|
||||
eventType, err := w.eventTypeFor(event)
|
||||
if err != nil {
|
||||
return eventstream.Message{}, err
|
||||
}
|
||||
|
||||
msg, err := event.MarshalEvent(w.payloadMarshaler)
|
||||
if err != nil {
|
||||
return eventstream.Message{}, err
|
||||
}
|
||||
|
||||
msg.Headers.Set(EventTypeHeader, eventstream.StringValue(eventType))
|
||||
return msg, nil
|
||||
}
|
||||
|
||||
//type EventEncoder struct {
|
||||
// encoder Encoder
|
||||
// ppayloadMarshaler protocol.PayloadMarshaler
|
||||
// eventTypeFor func(Marshaler) (string, error)
|
||||
//}
|
||||
//
|
||||
//func (e EventEncoder) Encode(event Marshaler) error {
|
||||
// msg, err := e.marshal(event)
|
||||
// if err != nil {
|
||||
// return err
|
||||
// }
|
||||
//
|
||||
// return w.encoder.Encode(msg)
|
||||
//}
|
||||
//
|
||||
//func (e EventEncoder) marshal(event Marshaler) (eventstream.Message, error) {
|
||||
// eventType, err := w.eventTypeFor(event)
|
||||
// if err != nil {
|
||||
// return eventstream.Message{}, err
|
||||
// }
|
||||
//
|
||||
// msg, err := event.MarshalEvent(w.payloadMarshaler)
|
||||
// if err != nil {
|
||||
// return eventstream.Message{}, err
|
||||
// }
|
||||
//
|
||||
// msg.Headers.Set(EventTypeHeader, eventstream.StringValue(eventType))
|
||||
// return msg, nil
|
||||
//}
|
||||
//
|
||||
//func (w *EventWriter) marshal(event Marshaler) (eventstream.Message, error) {
|
||||
// eventType, err := w.eventTypeFor(event)
|
||||
// if err != nil {
|
||||
// return eventstream.Message{}, err
|
||||
// }
|
||||
//
|
||||
// msg, err := event.MarshalEvent(w.payloadMarshaler)
|
||||
// if err != nil {
|
||||
// return eventstream.Message{}, err
|
||||
// }
|
||||
//
|
||||
// msg.Headers.Set(EventTypeHeader, eventstream.StringValue(eventType))
|
||||
// return msg, nil
|
||||
//}
|
||||
//
|
||||
5
vendor/github.com/aws/aws-sdk-go/private/protocol/eventstream/header_value.go
generated
vendored
5
vendor/github.com/aws/aws-sdk-go/private/protocol/eventstream/header_value.go
generated
vendored
@@ -461,6 +461,11 @@ func (v *TimestampValue) decode(r io.Reader) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// MarshalJSON implements the json.Marshaler interface
|
||||
func (v TimestampValue) MarshalJSON() ([]byte, error) {
|
||||
return []byte(v.String()), nil
|
||||
}
|
||||
|
||||
func timeFromEpochMilli(t int64) time.Time {
|
||||
secs := t / 1e3
|
||||
msec := t % 1e3
|
||||
|
||||
2
vendor/github.com/aws/aws-sdk-go/private/protocol/eventstream/message.go
generated
vendored
2
vendor/github.com/aws/aws-sdk-go/private/protocol/eventstream/message.go
generated
vendored
@@ -27,7 +27,7 @@ func (m *Message) rawMessage() (rawMessage, error) {
|
||||
|
||||
if len(m.Headers) > 0 {
|
||||
var headers bytes.Buffer
|
||||
if err := encodeHeaders(&headers, m.Headers); err != nil {
|
||||
if err := EncodeHeaders(&headers, m.Headers); err != nil {
|
||||
return rawMessage{}, err
|
||||
}
|
||||
raw.Headers = headers.Bytes()
|
||||
|
||||
2
vendor/github.com/aws/aws-sdk-go/private/protocol/payload.go
generated
vendored
2
vendor/github.com/aws/aws-sdk-go/private/protocol/payload.go
generated
vendored
@@ -64,7 +64,7 @@ func (h HandlerPayloadMarshal) MarshalPayload(w io.Writer, v interface{}) error
|
||||
metadata.ClientInfo{},
|
||||
request.Handlers{},
|
||||
nil,
|
||||
&request.Operation{HTTPMethod: "GET"},
|
||||
&request.Operation{HTTPMethod: "PUT"},
|
||||
v,
|
||||
nil,
|
||||
)
|
||||
|
||||
49
vendor/github.com/aws/aws-sdk-go/private/protocol/protocol.go
generated
vendored
Normal file
49
vendor/github.com/aws/aws-sdk-go/private/protocol/protocol.go
generated
vendored
Normal file
@@ -0,0 +1,49 @@
|
||||
package protocol
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws/awserr"
|
||||
"github.com/aws/aws-sdk-go/aws/request"
|
||||
)
|
||||
|
||||
// RequireHTTPMinProtocol request handler is used to enforce that
|
||||
// the target endpoint supports the given major and minor HTTP protocol version.
|
||||
type RequireHTTPMinProtocol struct {
|
||||
Major, Minor int
|
||||
}
|
||||
|
||||
// Handler will mark the request.Request with an error if the
|
||||
// target endpoint did not connect with the required HTTP protocol
|
||||
// major and minor version.
|
||||
func (p RequireHTTPMinProtocol) Handler(r *request.Request) {
|
||||
if r.Error != nil || r.HTTPResponse == nil {
|
||||
return
|
||||
}
|
||||
|
||||
if !strings.HasPrefix(r.HTTPResponse.Proto, "HTTP") {
|
||||
r.Error = newMinHTTPProtoError(p.Major, p.Minor, r)
|
||||
}
|
||||
|
||||
if r.HTTPResponse.ProtoMajor < p.Major || r.HTTPResponse.ProtoMinor < p.Minor {
|
||||
r.Error = newMinHTTPProtoError(p.Major, p.Minor, r)
|
||||
}
|
||||
}
|
||||
|
||||
// ErrCodeMinimumHTTPProtocolError error code is returned when the target endpoint
|
||||
// did not match the required HTTP major and minor protocol version.
|
||||
const ErrCodeMinimumHTTPProtocolError = "MinimumHTTPProtocolError"
|
||||
|
||||
func newMinHTTPProtoError(major, minor int, r *request.Request) error {
|
||||
return awserr.NewRequestFailure(
|
||||
awserr.New("MinimumHTTPProtocolError",
|
||||
fmt.Sprintf(
|
||||
"operation requires minimum HTTP protocol of HTTP/%d.%d, but was %s",
|
||||
major, minor, r.HTTPResponse.Proto,
|
||||
),
|
||||
nil,
|
||||
),
|
||||
r.HTTPResponse.StatusCode, r.RequestID,
|
||||
)
|
||||
}
|
||||
78
vendor/github.com/aws/aws-sdk-go/private/protocol/rest/unmarshal.go
generated
vendored
78
vendor/github.com/aws/aws-sdk-go/private/protocol/rest/unmarshal.go
generated
vendored
@@ -15,6 +15,7 @@ import (
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/awserr"
|
||||
"github.com/aws/aws-sdk-go/aws/request"
|
||||
awsStrings "github.com/aws/aws-sdk-go/internal/strings"
|
||||
"github.com/aws/aws-sdk-go/private/protocol"
|
||||
)
|
||||
|
||||
@@ -28,7 +29,9 @@ var UnmarshalMetaHandler = request.NamedHandler{Name: "awssdk.rest.UnmarshalMeta
|
||||
func Unmarshal(r *request.Request) {
|
||||
if r.DataFilled() {
|
||||
v := reflect.Indirect(reflect.ValueOf(r.Data))
|
||||
unmarshalBody(r, v)
|
||||
if err := unmarshalBody(r, v); err != nil {
|
||||
r.Error = err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,12 +43,21 @@ func UnmarshalMeta(r *request.Request) {
|
||||
r.RequestID = r.HTTPResponse.Header.Get("X-Amz-Request-Id")
|
||||
}
|
||||
if r.DataFilled() {
|
||||
v := reflect.Indirect(reflect.ValueOf(r.Data))
|
||||
unmarshalLocationElements(r, v)
|
||||
if err := UnmarshalResponse(r.HTTPResponse, r.Data, aws.BoolValue(r.Config.LowerCaseHeaderMaps)); err != nil {
|
||||
r.Error = err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func unmarshalBody(r *request.Request, v reflect.Value) {
|
||||
// UnmarshalResponse attempts to unmarshal the REST response headers to
|
||||
// the data type passed in. The type must be a pointer. An error is returned
|
||||
// with any error unmarshaling the response into the target datatype.
|
||||
func UnmarshalResponse(resp *http.Response, data interface{}, lowerCaseHeaderMaps bool) error {
|
||||
v := reflect.Indirect(reflect.ValueOf(data))
|
||||
return unmarshalLocationElements(resp, v, lowerCaseHeaderMaps)
|
||||
}
|
||||
|
||||
func unmarshalBody(r *request.Request, v reflect.Value) error {
|
||||
if field, ok := v.Type().FieldByName("_"); ok {
|
||||
if payloadName := field.Tag.Get("payload"); payloadName != "" {
|
||||
pfield, _ := v.Type().FieldByName(payloadName)
|
||||
@@ -57,35 +69,38 @@ func unmarshalBody(r *request.Request, v reflect.Value) {
|
||||
defer r.HTTPResponse.Body.Close()
|
||||
b, err := ioutil.ReadAll(r.HTTPResponse.Body)
|
||||
if err != nil {
|
||||
r.Error = awserr.New(request.ErrCodeSerialization, "failed to decode REST response", err)
|
||||
} else {
|
||||
payload.Set(reflect.ValueOf(b))
|
||||
return awserr.New(request.ErrCodeSerialization, "failed to decode REST response", err)
|
||||
}
|
||||
|
||||
payload.Set(reflect.ValueOf(b))
|
||||
|
||||
case *string:
|
||||
defer r.HTTPResponse.Body.Close()
|
||||
b, err := ioutil.ReadAll(r.HTTPResponse.Body)
|
||||
if err != nil {
|
||||
r.Error = awserr.New(request.ErrCodeSerialization, "failed to decode REST response", err)
|
||||
} else {
|
||||
str := string(b)
|
||||
payload.Set(reflect.ValueOf(&str))
|
||||
return awserr.New(request.ErrCodeSerialization, "failed to decode REST response", err)
|
||||
}
|
||||
|
||||
str := string(b)
|
||||
payload.Set(reflect.ValueOf(&str))
|
||||
|
||||
default:
|
||||
switch payload.Type().String() {
|
||||
case "io.ReadCloser":
|
||||
payload.Set(reflect.ValueOf(r.HTTPResponse.Body))
|
||||
|
||||
case "io.ReadSeeker":
|
||||
b, err := ioutil.ReadAll(r.HTTPResponse.Body)
|
||||
if err != nil {
|
||||
r.Error = awserr.New(request.ErrCodeSerialization,
|
||||
return awserr.New(request.ErrCodeSerialization,
|
||||
"failed to read response body", err)
|
||||
return
|
||||
}
|
||||
payload.Set(reflect.ValueOf(ioutil.NopCloser(bytes.NewReader(b))))
|
||||
|
||||
default:
|
||||
io.Copy(ioutil.Discard, r.HTTPResponse.Body)
|
||||
defer r.HTTPResponse.Body.Close()
|
||||
r.Error = awserr.New(request.ErrCodeSerialization,
|
||||
r.HTTPResponse.Body.Close()
|
||||
return awserr.New(request.ErrCodeSerialization,
|
||||
"failed to decode REST response",
|
||||
fmt.Errorf("unknown payload type %s", payload.Type()))
|
||||
}
|
||||
@@ -94,9 +109,11 @@ func unmarshalBody(r *request.Request, v reflect.Value) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func unmarshalLocationElements(r *request.Request, v reflect.Value) {
|
||||
func unmarshalLocationElements(resp *http.Response, v reflect.Value, lowerCaseHeaderMaps bool) error {
|
||||
for i := 0; i < v.NumField(); i++ {
|
||||
m, field := v.Field(i), v.Type().Field(i)
|
||||
if n := field.Name; n[0:1] == strings.ToLower(n[0:1]) {
|
||||
@@ -111,26 +128,25 @@ func unmarshalLocationElements(r *request.Request, v reflect.Value) {
|
||||
|
||||
switch field.Tag.Get("location") {
|
||||
case "statusCode":
|
||||
unmarshalStatusCode(m, r.HTTPResponse.StatusCode)
|
||||
unmarshalStatusCode(m, resp.StatusCode)
|
||||
|
||||
case "header":
|
||||
err := unmarshalHeader(m, r.HTTPResponse.Header.Get(name), field.Tag)
|
||||
err := unmarshalHeader(m, resp.Header.Get(name), field.Tag)
|
||||
if err != nil {
|
||||
r.Error = awserr.New(request.ErrCodeSerialization, "failed to decode REST response", err)
|
||||
break
|
||||
return awserr.New(request.ErrCodeSerialization, "failed to decode REST response", err)
|
||||
}
|
||||
|
||||
case "headers":
|
||||
prefix := field.Tag.Get("locationName")
|
||||
err := unmarshalHeaderMap(m, r.HTTPResponse.Header, prefix)
|
||||
err := unmarshalHeaderMap(m, resp.Header, prefix, lowerCaseHeaderMaps)
|
||||
if err != nil {
|
||||
r.Error = awserr.New(request.ErrCodeSerialization, "failed to decode REST response", err)
|
||||
break
|
||||
awserr.New(request.ErrCodeSerialization, "failed to decode REST response", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
if r.Error != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func unmarshalStatusCode(v reflect.Value, statusCode int) {
|
||||
@@ -145,7 +161,7 @@ func unmarshalStatusCode(v reflect.Value, statusCode int) {
|
||||
}
|
||||
}
|
||||
|
||||
func unmarshalHeaderMap(r reflect.Value, headers http.Header, prefix string) error {
|
||||
func unmarshalHeaderMap(r reflect.Value, headers http.Header, prefix string, normalize bool) error {
|
||||
if len(headers) == 0 {
|
||||
return nil
|
||||
}
|
||||
@@ -153,8 +169,12 @@ func unmarshalHeaderMap(r reflect.Value, headers http.Header, prefix string) err
|
||||
case map[string]*string: // we only support string map value types
|
||||
out := map[string]*string{}
|
||||
for k, v := range headers {
|
||||
k = http.CanonicalHeaderKey(k)
|
||||
if strings.HasPrefix(strings.ToLower(k), strings.ToLower(prefix)) {
|
||||
if awsStrings.HasPrefixFold(k, prefix) {
|
||||
if normalize == true {
|
||||
k = strings.ToLower(k)
|
||||
} else {
|
||||
k = http.CanonicalHeaderKey(k)
|
||||
}
|
||||
out[k[len(prefix):]] = &v[0]
|
||||
}
|
||||
}
|
||||
|
||||
6
vendor/github.com/aws/aws-sdk-go/private/protocol/unmarshal.go
generated
vendored
6
vendor/github.com/aws/aws-sdk-go/private/protocol/unmarshal.go
generated
vendored
@@ -19,3 +19,9 @@ func UnmarshalDiscardBody(r *request.Request) {
|
||||
io.Copy(ioutil.Discard, r.HTTPResponse.Body)
|
||||
r.HTTPResponse.Body.Close()
|
||||
}
|
||||
|
||||
// ResponseMetadata provides the SDK response metadata attributes.
|
||||
type ResponseMetadata struct {
|
||||
StatusCode int
|
||||
RequestID string
|
||||
}
|
||||
|
||||
65
vendor/github.com/aws/aws-sdk-go/private/protocol/unmarshal_error.go
generated
vendored
Normal file
65
vendor/github.com/aws/aws-sdk-go/private/protocol/unmarshal_error.go
generated
vendored
Normal file
@@ -0,0 +1,65 @@
|
||||
package protocol
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws/awserr"
|
||||
"github.com/aws/aws-sdk-go/aws/request"
|
||||
)
|
||||
|
||||
// UnmarshalErrorHandler provides unmarshaling errors API response errors for
|
||||
// both typed and untyped errors.
|
||||
type UnmarshalErrorHandler struct {
|
||||
unmarshaler ErrorUnmarshaler
|
||||
}
|
||||
|
||||
// ErrorUnmarshaler is an abstract interface for concrete implementations to
|
||||
// unmarshal protocol specific response errors.
|
||||
type ErrorUnmarshaler interface {
|
||||
UnmarshalError(*http.Response, ResponseMetadata) (error, error)
|
||||
}
|
||||
|
||||
// NewUnmarshalErrorHandler returns an UnmarshalErrorHandler
|
||||
// initialized for the set of exception names to the error unmarshalers
|
||||
func NewUnmarshalErrorHandler(unmarshaler ErrorUnmarshaler) *UnmarshalErrorHandler {
|
||||
return &UnmarshalErrorHandler{
|
||||
unmarshaler: unmarshaler,
|
||||
}
|
||||
}
|
||||
|
||||
// UnmarshalErrorHandlerName is the name of the named handler.
|
||||
const UnmarshalErrorHandlerName = "awssdk.protocol.UnmarshalError"
|
||||
|
||||
// NamedHandler returns a NamedHandler for the unmarshaler using the set of
|
||||
// errors the unmarshaler was initialized for.
|
||||
func (u *UnmarshalErrorHandler) NamedHandler() request.NamedHandler {
|
||||
return request.NamedHandler{
|
||||
Name: UnmarshalErrorHandlerName,
|
||||
Fn: u.UnmarshalError,
|
||||
}
|
||||
}
|
||||
|
||||
// UnmarshalError will attempt to unmarshal the API response's error message
|
||||
// into either a generic SDK error type, or a typed error corresponding to the
|
||||
// errors exception name.
|
||||
func (u *UnmarshalErrorHandler) UnmarshalError(r *request.Request) {
|
||||
defer r.HTTPResponse.Body.Close()
|
||||
|
||||
respMeta := ResponseMetadata{
|
||||
StatusCode: r.HTTPResponse.StatusCode,
|
||||
RequestID: r.RequestID,
|
||||
}
|
||||
|
||||
v, err := u.unmarshaler.UnmarshalError(r.HTTPResponse, respMeta)
|
||||
if err != nil {
|
||||
r.Error = awserr.NewRequestFailure(
|
||||
awserr.New(request.ErrCodeSerialization,
|
||||
"failed to unmarshal response error", err),
|
||||
respMeta.StatusCode,
|
||||
respMeta.RequestID,
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
r.Error = v
|
||||
}
|
||||
363
vendor/github.com/aws/aws-sdk-go/service/s3/api.go
generated
vendored
363
vendor/github.com/aws/aws-sdk-go/service/s3/api.go
generated
vendored
@@ -7,7 +7,6 @@ import (
|
||||
"fmt"
|
||||
"io"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
@@ -9496,9 +9495,15 @@ func (c *S3) SelectObjectContentRequest(input *SelectObjectContentInput) (req *r
|
||||
|
||||
output = &SelectObjectContentOutput{}
|
||||
req = c.newRequest(op, input, output)
|
||||
|
||||
es := newSelectObjectContentEventStream()
|
||||
req.Handlers.Unmarshal.PushBack(es.setStreamCloser)
|
||||
output.EventStream = es
|
||||
|
||||
req.Handlers.Send.Swap(client.LogHTTPResponseHandler.Name, client.LogHTTPResponseHeaderHandler)
|
||||
req.Handlers.Unmarshal.Swap(restxml.UnmarshalHandler.Name, rest.UnmarshalHandler)
|
||||
req.Handlers.Unmarshal.PushBack(output.runEventStreamLoop)
|
||||
req.Handlers.Unmarshal.PushBack(es.runOutputStream)
|
||||
req.Handlers.Unmarshal.PushBack(es.runOnStreamPartClose)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -9617,6 +9622,147 @@ func (c *S3) SelectObjectContentWithContext(ctx aws.Context, input *SelectObject
|
||||
return out, req.Send()
|
||||
}
|
||||
|
||||
// SelectObjectContentEventStream provides the event stream handling for the SelectObjectContent.
|
||||
type SelectObjectContentEventStream struct {
|
||||
|
||||
// Reader is the EventStream reader for the SelectObjectContentEventStream
|
||||
// events. This value is automatically set by the SDK when the API call is made
|
||||
// Use this member when unit testing your code with the SDK to mock out the
|
||||
// EventStream Reader.
|
||||
//
|
||||
// Must not be nil.
|
||||
Reader SelectObjectContentEventStreamReader
|
||||
|
||||
outputReader io.ReadCloser
|
||||
|
||||
// StreamCloser is the io.Closer for the EventStream connection. For HTTP
|
||||
// EventStream this is the response Body. The stream will be closed when
|
||||
// the Close method of the EventStream is called.
|
||||
StreamCloser io.Closer
|
||||
|
||||
done chan struct{}
|
||||
closeOnce sync.Once
|
||||
err *eventstreamapi.OnceError
|
||||
}
|
||||
|
||||
func newSelectObjectContentEventStream() *SelectObjectContentEventStream {
|
||||
return &SelectObjectContentEventStream{
|
||||
done: make(chan struct{}),
|
||||
err: eventstreamapi.NewOnceError(),
|
||||
}
|
||||
}
|
||||
|
||||
func (es *SelectObjectContentEventStream) setStreamCloser(r *request.Request) {
|
||||
es.StreamCloser = r.HTTPResponse.Body
|
||||
}
|
||||
|
||||
func (es *SelectObjectContentEventStream) runOnStreamPartClose(r *request.Request) {
|
||||
if es.done == nil {
|
||||
return
|
||||
}
|
||||
go es.waitStreamPartClose()
|
||||
|
||||
}
|
||||
|
||||
func (es *SelectObjectContentEventStream) waitStreamPartClose() {
|
||||
var outputErrCh <-chan struct{}
|
||||
if v, ok := es.Reader.(interface{ ErrorSet() <-chan struct{} }); ok {
|
||||
outputErrCh = v.ErrorSet()
|
||||
}
|
||||
var outputClosedCh <-chan struct{}
|
||||
if v, ok := es.Reader.(interface{ Closed() <-chan struct{} }); ok {
|
||||
outputClosedCh = v.Closed()
|
||||
}
|
||||
|
||||
select {
|
||||
case <-es.done:
|
||||
case <-outputErrCh:
|
||||
es.err.SetError(es.Reader.Err())
|
||||
es.Close()
|
||||
case <-outputClosedCh:
|
||||
if err := es.Reader.Err(); err != nil {
|
||||
es.err.SetError(es.Reader.Err())
|
||||
}
|
||||
es.Close()
|
||||
}
|
||||
}
|
||||
|
||||
// Events returns a channel to read events from.
|
||||
//
|
||||
// These events are:
|
||||
//
|
||||
// * ContinuationEvent
|
||||
// * EndEvent
|
||||
// * ProgressEvent
|
||||
// * RecordsEvent
|
||||
// * StatsEvent
|
||||
func (es *SelectObjectContentEventStream) Events() <-chan SelectObjectContentEventStreamEvent {
|
||||
return es.Reader.Events()
|
||||
}
|
||||
|
||||
func (es *SelectObjectContentEventStream) runOutputStream(r *request.Request) {
|
||||
var opts []func(*eventstream.Decoder)
|
||||
if r.Config.Logger != nil && r.Config.LogLevel.Matches(aws.LogDebugWithEventStreamBody) {
|
||||
opts = append(opts, eventstream.DecodeWithLogger(r.Config.Logger))
|
||||
}
|
||||
|
||||
unmarshalerForEvent := unmarshalerForSelectObjectContentEventStreamEvent{
|
||||
metadata: protocol.ResponseMetadata{
|
||||
StatusCode: r.HTTPResponse.StatusCode,
|
||||
RequestID: r.RequestID,
|
||||
},
|
||||
}.UnmarshalerForEventName
|
||||
|
||||
decoder := eventstream.NewDecoder(r.HTTPResponse.Body, opts...)
|
||||
eventReader := eventstreamapi.NewEventReader(decoder,
|
||||
protocol.HandlerPayloadUnmarshal{
|
||||
Unmarshalers: r.Handlers.UnmarshalStream,
|
||||
},
|
||||
unmarshalerForEvent,
|
||||
)
|
||||
|
||||
es.outputReader = r.HTTPResponse.Body
|
||||
es.Reader = newReadSelectObjectContentEventStream(eventReader)
|
||||
}
|
||||
|
||||
// Close closes the stream. This will also cause the stream to be closed.
|
||||
// Close must be called when done using the stream API. Not calling Close
|
||||
// may result in resource leaks.
|
||||
//
|
||||
// You can use the closing of the Reader's Events channel to terminate your
|
||||
// application's read from the API's stream.
|
||||
//
|
||||
func (es *SelectObjectContentEventStream) Close() (err error) {
|
||||
es.closeOnce.Do(es.safeClose)
|
||||
return es.Err()
|
||||
}
|
||||
|
||||
func (es *SelectObjectContentEventStream) safeClose() {
|
||||
if es.done != nil {
|
||||
close(es.done)
|
||||
}
|
||||
|
||||
es.Reader.Close()
|
||||
if es.outputReader != nil {
|
||||
es.outputReader.Close()
|
||||
}
|
||||
|
||||
es.StreamCloser.Close()
|
||||
}
|
||||
|
||||
// Err returns any error that occurred while reading or writing EventStream
|
||||
// Events from the service API's response. Returns nil if there were no errors.
|
||||
func (es *SelectObjectContentEventStream) Err() error {
|
||||
if err := es.err.Err(); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := es.Reader.Err(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
const opUploadPart = "UploadPart"
|
||||
|
||||
// UploadPartRequest generates a "aws/request.Request" representing the
|
||||
@@ -11432,6 +11578,11 @@ func (s *ContinuationEvent) UnmarshalEvent(
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *ContinuationEvent) MarshalEvent(pm protocol.PayloadMarshaler) (msg eventstream.Message, err error) {
|
||||
msg.Headers.Set(eventstreamapi.MessageTypeHeader, eventstream.StringValue(eventstreamapi.EventMessageType))
|
||||
return msg, err
|
||||
}
|
||||
|
||||
type CopyObjectInput struct {
|
||||
_ struct{} `locationName:"CopyObjectRequest" type:"structure"`
|
||||
|
||||
@@ -14643,6 +14794,11 @@ func (s *EndEvent) UnmarshalEvent(
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *EndEvent) MarshalEvent(pm protocol.PayloadMarshaler) (msg eventstream.Message, err error) {
|
||||
msg.Headers.Set(eventstreamapi.MessageTypeHeader, eventstream.StringValue(eventstreamapi.EventMessageType))
|
||||
return msg, err
|
||||
}
|
||||
|
||||
// Container for all error elements.
|
||||
type Error struct {
|
||||
_ struct{} `type:"structure"`
|
||||
@@ -17543,6 +17699,10 @@ type GetObjectOutput struct {
|
||||
LastModified *time.Time `location:"header" locationName:"Last-Modified" type:"timestamp"`
|
||||
|
||||
// A map of metadata to store with the object in S3.
|
||||
//
|
||||
// By default unmarshaled keys are written as a map keys in following canonicalized format:
|
||||
// the first letter and any letter following a hyphen will be capitalized, and the rest as lowercase.
|
||||
// Set `aws.Config.LowerCaseHeaderMaps` to `true` to write unmarshaled keys to the map as lowercase.
|
||||
Metadata map[string]*string `location:"headers" locationName:"x-amz-meta-" type:"map"`
|
||||
|
||||
// This is set to the number of metadata entries not returned in x-amz-meta
|
||||
@@ -18770,6 +18930,10 @@ type HeadObjectOutput struct {
|
||||
LastModified *time.Time `location:"header" locationName:"Last-Modified" type:"timestamp"`
|
||||
|
||||
// A map of metadata to store with the object in S3.
|
||||
//
|
||||
// By default unmarshaled keys are written as a map keys in following canonicalized format:
|
||||
// the first letter and any letter following a hyphen will be capitalized, and the rest as lowercase.
|
||||
// Set `aws.Config.LowerCaseHeaderMaps` to `true` to write unmarshaled keys to the map as lowercase.
|
||||
Metadata map[string]*string `location:"headers" locationName:"x-amz-meta-" type:"map"`
|
||||
|
||||
// This is set to the number of metadata entries not returned in x-amz-meta
|
||||
@@ -23366,6 +23530,16 @@ func (s *ProgressEvent) UnmarshalEvent(
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *ProgressEvent) MarshalEvent(pm protocol.PayloadMarshaler) (msg eventstream.Message, err error) {
|
||||
msg.Headers.Set(eventstreamapi.MessageTypeHeader, eventstream.StringValue(eventstreamapi.EventMessageType))
|
||||
var buf bytes.Buffer
|
||||
if err = pm.MarshalPayload(&buf, s); err != nil {
|
||||
return eventstream.Message{}, err
|
||||
}
|
||||
msg.Payload = buf.Bytes()
|
||||
return msg, err
|
||||
}
|
||||
|
||||
// The PublicAccessBlock configuration that you want to apply to this Amazon
|
||||
// S3 bucket. You can enable the configuration options in any combination. For
|
||||
// more information about when Amazon S3 considers a bucket or object public,
|
||||
@@ -26792,6 +26966,13 @@ func (s *RecordsEvent) UnmarshalEvent(
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *RecordsEvent) MarshalEvent(pm protocol.PayloadMarshaler) (msg eventstream.Message, err error) {
|
||||
msg.Headers.Set(eventstreamapi.MessageTypeHeader, eventstream.StringValue(eventstreamapi.EventMessageType))
|
||||
msg.Headers.Set(":content-type", eventstream.StringValue("application/octet-stream"))
|
||||
msg.Payload = s.Payload
|
||||
return msg, err
|
||||
}
|
||||
|
||||
// Specifies how requests are redirected. In the event of an error, you can
|
||||
// specify a different error code to return.
|
||||
type Redirect struct {
|
||||
@@ -27973,75 +28154,8 @@ func (s *ScanRange) SetStart(v int64) *ScanRange {
|
||||
return s
|
||||
}
|
||||
|
||||
// SelectObjectContentEventStream provides handling of EventStreams for
|
||||
// the SelectObjectContent API.
|
||||
//
|
||||
// Use this type to receive SelectObjectContentEventStream events. The events
|
||||
// can be read from the Events channel member.
|
||||
//
|
||||
// The events that can be received are:
|
||||
//
|
||||
// * ContinuationEvent
|
||||
// * EndEvent
|
||||
// * ProgressEvent
|
||||
// * RecordsEvent
|
||||
// * StatsEvent
|
||||
type SelectObjectContentEventStream struct {
|
||||
// Reader is the EventStream reader for the SelectObjectContentEventStream
|
||||
// events. This value is automatically set by the SDK when the API call is made
|
||||
// Use this member when unit testing your code with the SDK to mock out the
|
||||
// EventStream Reader.
|
||||
//
|
||||
// Must not be nil.
|
||||
Reader SelectObjectContentEventStreamReader
|
||||
|
||||
// StreamCloser is the io.Closer for the EventStream connection. For HTTP
|
||||
// EventStream this is the response Body. The stream will be closed when
|
||||
// the Close method of the EventStream is called.
|
||||
StreamCloser io.Closer
|
||||
}
|
||||
|
||||
// Close closes the EventStream. This will also cause the Events channel to be
|
||||
// closed. You can use the closing of the Events channel to terminate your
|
||||
// application's read from the API's EventStream.
|
||||
//
|
||||
// Will close the underlying EventStream reader. For EventStream over HTTP
|
||||
// connection this will also close the HTTP connection.
|
||||
//
|
||||
// Close must be called when done using the EventStream API. Not calling Close
|
||||
// may result in resource leaks.
|
||||
func (es *SelectObjectContentEventStream) Close() (err error) {
|
||||
es.Reader.Close()
|
||||
es.StreamCloser.Close()
|
||||
|
||||
return es.Err()
|
||||
}
|
||||
|
||||
// Err returns any error that occurred while reading EventStream Events from
|
||||
// the service API's response. Returns nil if there were no errors.
|
||||
func (es *SelectObjectContentEventStream) Err() error {
|
||||
if err := es.Reader.Err(); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Events returns a channel to read EventStream Events from the
|
||||
// SelectObjectContent API.
|
||||
//
|
||||
// These events are:
|
||||
//
|
||||
// * ContinuationEvent
|
||||
// * EndEvent
|
||||
// * ProgressEvent
|
||||
// * RecordsEvent
|
||||
// * StatsEvent
|
||||
func (es *SelectObjectContentEventStream) Events() <-chan SelectObjectContentEventStreamEvent {
|
||||
return es.Reader.Events()
|
||||
}
|
||||
|
||||
// SelectObjectContentEventStreamEvent groups together all EventStream
|
||||
// events read from the SelectObjectContent API.
|
||||
// events writes for SelectObjectContentEventStream.
|
||||
//
|
||||
// These events are:
|
||||
//
|
||||
@@ -28052,11 +28166,12 @@ func (es *SelectObjectContentEventStream) Events() <-chan SelectObjectContentEve
|
||||
// * StatsEvent
|
||||
type SelectObjectContentEventStreamEvent interface {
|
||||
eventSelectObjectContentEventStream()
|
||||
eventstreamapi.Marshaler
|
||||
eventstreamapi.Unmarshaler
|
||||
}
|
||||
|
||||
// SelectObjectContentEventStreamReader provides the interface for reading EventStream
|
||||
// Events from the SelectObjectContent API. The
|
||||
// default implementation for this interface will be SelectObjectContentEventStream.
|
||||
// SelectObjectContentEventStreamReader provides the interface for reading to the stream. The
|
||||
// default implementation for this interface will be SelectObjectContentEventStreamData.
|
||||
//
|
||||
// The reader's Close method must allow multiple concurrent calls.
|
||||
//
|
||||
@@ -28071,8 +28186,7 @@ type SelectObjectContentEventStreamReader interface {
|
||||
// Returns a channel of events as they are read from the event stream.
|
||||
Events() <-chan SelectObjectContentEventStreamEvent
|
||||
|
||||
// Close will close the underlying event stream reader. For event stream over
|
||||
// HTTP this will also close the HTTP connection.
|
||||
// Close will stop the reader reading events from the stream.
|
||||
Close() error
|
||||
|
||||
// Returns any error that has occurred while reading from the event stream.
|
||||
@@ -28082,57 +28196,44 @@ type SelectObjectContentEventStreamReader interface {
|
||||
type readSelectObjectContentEventStream struct {
|
||||
eventReader *eventstreamapi.EventReader
|
||||
stream chan SelectObjectContentEventStreamEvent
|
||||
errVal atomic.Value
|
||||
err *eventstreamapi.OnceError
|
||||
|
||||
done chan struct{}
|
||||
closeOnce sync.Once
|
||||
}
|
||||
|
||||
func newReadSelectObjectContentEventStream(
|
||||
reader io.ReadCloser,
|
||||
unmarshalers request.HandlerList,
|
||||
logger aws.Logger,
|
||||
logLevel aws.LogLevelType,
|
||||
) *readSelectObjectContentEventStream {
|
||||
func newReadSelectObjectContentEventStream(eventReader *eventstreamapi.EventReader) *readSelectObjectContentEventStream {
|
||||
r := &readSelectObjectContentEventStream{
|
||||
stream: make(chan SelectObjectContentEventStreamEvent),
|
||||
done: make(chan struct{}),
|
||||
eventReader: eventReader,
|
||||
stream: make(chan SelectObjectContentEventStreamEvent),
|
||||
done: make(chan struct{}),
|
||||
err: eventstreamapi.NewOnceError(),
|
||||
}
|
||||
|
||||
r.eventReader = eventstreamapi.NewEventReader(
|
||||
reader,
|
||||
protocol.HandlerPayloadUnmarshal{
|
||||
Unmarshalers: unmarshalers,
|
||||
},
|
||||
r.unmarshalerForEventType,
|
||||
)
|
||||
r.eventReader.UseLogger(logger, logLevel)
|
||||
go r.readEventStream()
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
// Close will close the underlying event stream reader. For EventStream over
|
||||
// HTTP this will also close the HTTP connection.
|
||||
// Close will close the underlying event stream reader.
|
||||
func (r *readSelectObjectContentEventStream) Close() error {
|
||||
r.closeOnce.Do(r.safeClose)
|
||||
|
||||
return r.Err()
|
||||
}
|
||||
|
||||
func (r *readSelectObjectContentEventStream) ErrorSet() <-chan struct{} {
|
||||
return r.err.ErrorSet()
|
||||
}
|
||||
|
||||
func (r *readSelectObjectContentEventStream) Closed() <-chan struct{} {
|
||||
return r.done
|
||||
}
|
||||
|
||||
func (r *readSelectObjectContentEventStream) safeClose() {
|
||||
close(r.done)
|
||||
err := r.eventReader.Close()
|
||||
if err != nil {
|
||||
r.errVal.Store(err)
|
||||
}
|
||||
}
|
||||
|
||||
func (r *readSelectObjectContentEventStream) Err() error {
|
||||
if v := r.errVal.Load(); v != nil {
|
||||
return v.(error)
|
||||
}
|
||||
|
||||
return nil
|
||||
return r.err.Err()
|
||||
}
|
||||
|
||||
func (r *readSelectObjectContentEventStream) Events() <-chan SelectObjectContentEventStreamEvent {
|
||||
@@ -28140,6 +28241,7 @@ func (r *readSelectObjectContentEventStream) Events() <-chan SelectObjectContent
|
||||
}
|
||||
|
||||
func (r *readSelectObjectContentEventStream) readEventStream() {
|
||||
defer r.Close()
|
||||
defer close(r.stream)
|
||||
|
||||
for {
|
||||
@@ -28154,7 +28256,7 @@ func (r *readSelectObjectContentEventStream) readEventStream() {
|
||||
return
|
||||
default:
|
||||
}
|
||||
r.errVal.Store(err)
|
||||
r.err.SetError(err)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -28166,22 +28268,20 @@ func (r *readSelectObjectContentEventStream) readEventStream() {
|
||||
}
|
||||
}
|
||||
|
||||
func (r *readSelectObjectContentEventStream) unmarshalerForEventType(
|
||||
eventType string,
|
||||
) (eventstreamapi.Unmarshaler, error) {
|
||||
type unmarshalerForSelectObjectContentEventStreamEvent struct {
|
||||
metadata protocol.ResponseMetadata
|
||||
}
|
||||
|
||||
func (u unmarshalerForSelectObjectContentEventStreamEvent) UnmarshalerForEventName(eventType string) (eventstreamapi.Unmarshaler, error) {
|
||||
switch eventType {
|
||||
case "Cont":
|
||||
return &ContinuationEvent{}, nil
|
||||
|
||||
case "End":
|
||||
return &EndEvent{}, nil
|
||||
|
||||
case "Progress":
|
||||
return &ProgressEvent{}, nil
|
||||
|
||||
case "Records":
|
||||
return &RecordsEvent{}, nil
|
||||
|
||||
case "Stats":
|
||||
return &StatsEvent{}, nil
|
||||
default:
|
||||
@@ -28408,8 +28508,7 @@ func (s *SelectObjectContentInput) hasEndpointARN() bool {
|
||||
type SelectObjectContentOutput struct {
|
||||
_ struct{} `type:"structure" payload:"Payload"`
|
||||
|
||||
// Use EventStream to use the API's stream.
|
||||
EventStream *SelectObjectContentEventStream `type:"structure"`
|
||||
EventStream *SelectObjectContentEventStream
|
||||
}
|
||||
|
||||
// String returns the string representation
|
||||
@@ -28422,29 +28521,17 @@ func (s SelectObjectContentOutput) GoString() string {
|
||||
return s.String()
|
||||
}
|
||||
|
||||
// SetEventStream sets the EventStream field's value.
|
||||
func (s *SelectObjectContentOutput) SetEventStream(v *SelectObjectContentEventStream) *SelectObjectContentOutput {
|
||||
s.EventStream = v
|
||||
return s
|
||||
}
|
||||
func (s *SelectObjectContentOutput) GetEventStream() *SelectObjectContentEventStream {
|
||||
return s.EventStream
|
||||
}
|
||||
|
||||
func (s *SelectObjectContentOutput) runEventStreamLoop(r *request.Request) {
|
||||
if r.Error != nil {
|
||||
return
|
||||
}
|
||||
reader := newReadSelectObjectContentEventStream(
|
||||
r.HTTPResponse.Body,
|
||||
r.Handlers.UnmarshalStream,
|
||||
r.Config.Logger,
|
||||
r.Config.LogLevel.Value(),
|
||||
)
|
||||
go reader.readEventStream()
|
||||
|
||||
eventStream := &SelectObjectContentEventStream{
|
||||
StreamCloser: r.HTTPResponse.Body,
|
||||
Reader: reader,
|
||||
}
|
||||
s.EventStream = eventStream
|
||||
// GetStream returns the type to interact with the event stream.
|
||||
func (s *SelectObjectContentOutput) GetStream() *SelectObjectContentEventStream {
|
||||
return s.EventStream
|
||||
}
|
||||
|
||||
// Describes the parameters for Select job types.
|
||||
@@ -28841,6 +28928,16 @@ func (s *StatsEvent) UnmarshalEvent(
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *StatsEvent) MarshalEvent(pm protocol.PayloadMarshaler) (msg eventstream.Message, err error) {
|
||||
msg.Headers.Set(eventstreamapi.MessageTypeHeader, eventstream.StringValue(eventstreamapi.EventMessageType))
|
||||
var buf bytes.Buffer
|
||||
if err = pm.MarshalPayload(&buf, s); err != nil {
|
||||
return eventstream.Message{}, err
|
||||
}
|
||||
msg.Payload = buf.Bytes()
|
||||
return msg, err
|
||||
}
|
||||
|
||||
// Specifies data related to access patterns to be collected and made available
|
||||
// to analyze the tradeoffs between different storage classes for an Amazon
|
||||
// S3 bucket.
|
||||
|
||||
33
vendor/github.com/aws/aws-sdk-go/service/s3/s3manager/upload.go
generated
vendored
33
vendor/github.com/aws/aws-sdk-go/service/s3/s3manager/upload.go
generated
vendored
@@ -167,7 +167,7 @@ type Uploader struct {
|
||||
BufferProvider ReadSeekerWriteToProvider
|
||||
|
||||
// partPool allows for the re-usage of streaming payload part buffers between upload calls
|
||||
partPool *partPool
|
||||
partPool byteSlicePool
|
||||
}
|
||||
|
||||
// NewUploader creates a new Uploader instance to upload objects to S3. Pass In
|
||||
@@ -204,7 +204,7 @@ func newUploader(client s3iface.S3API, options ...func(*Uploader)) *Uploader {
|
||||
option(u)
|
||||
}
|
||||
|
||||
u.partPool = newPartPool(u.PartSize)
|
||||
u.partPool = newByteSlicePool(u.PartSize)
|
||||
|
||||
return u
|
||||
}
|
||||
@@ -404,8 +404,8 @@ func (u *uploader) init() error {
|
||||
|
||||
// If PartSize was changed or partPool was never setup then we need to allocated a new pool
|
||||
// so that we return []byte slices of the correct size
|
||||
if u.cfg.partPool == nil || u.cfg.partPool.partSize != u.cfg.PartSize {
|
||||
u.cfg.partPool = newPartPool(u.cfg.PartSize)
|
||||
if u.cfg.partPool == nil || u.cfg.partPool.Size() != u.cfg.PartSize {
|
||||
u.cfg.partPool = newByteSlicePool(u.cfg.PartSize)
|
||||
}
|
||||
|
||||
return nil
|
||||
@@ -476,7 +476,7 @@ func (u *uploader) nextReader() (io.ReadSeeker, int, func(), error) {
|
||||
return reader, int(n), cleanup, err
|
||||
|
||||
default:
|
||||
part := u.cfg.partPool.Get().([]byte)
|
||||
part := u.cfg.partPool.Get()
|
||||
n, err := readFillBuf(r, part)
|
||||
u.readerPos += int64(n)
|
||||
|
||||
@@ -558,6 +558,7 @@ func (u *multiuploader) upload(firstBuf io.ReadSeeker, cleanup func()) (*UploadO
|
||||
// Create the multipart
|
||||
resp, err := u.cfg.S3.CreateMultipartUploadWithContext(u.ctx, params, u.cfg.RequestOptions...)
|
||||
if err != nil {
|
||||
cleanup()
|
||||
return nil, err
|
||||
}
|
||||
u.uploadID = *resp.UploadId
|
||||
@@ -762,11 +763,29 @@ func (u *multiuploader) complete() *s3.CompleteMultipartUploadOutput {
|
||||
return resp
|
||||
}
|
||||
|
||||
type byteSlicePool interface {
|
||||
Get() []byte
|
||||
Put([]byte)
|
||||
Size() int64
|
||||
}
|
||||
|
||||
type partPool struct {
|
||||
partSize int64
|
||||
sync.Pool
|
||||
}
|
||||
|
||||
func (p *partPool) Get() []byte {
|
||||
return p.Pool.Get().([]byte)
|
||||
}
|
||||
|
||||
func (p *partPool) Put(b []byte) {
|
||||
p.Pool.Put(b)
|
||||
}
|
||||
|
||||
func (p *partPool) Size() int64 {
|
||||
return p.partSize
|
||||
}
|
||||
|
||||
func newPartPool(partSize int64) *partPool {
|
||||
p := &partPool{partSize: partSize}
|
||||
|
||||
@@ -776,3 +795,7 @@ func newPartPool(partSize int64) *partPool {
|
||||
|
||||
return p
|
||||
}
|
||||
|
||||
var newByteSlicePool = func(partSize int64) byteSlicePool {
|
||||
return newPartPool(partSize)
|
||||
}
|
||||
|
||||
1
vendor/github.com/aws/aws-sdk-go/service/s3/service.go
generated
vendored
1
vendor/github.com/aws/aws-sdk-go/service/s3/service.go
generated
vendored
@@ -78,6 +78,7 @@ func newClient(cfg aws.Config, handlers request.Handlers, partitionID, endpoint,
|
||||
svc.Handlers.UnmarshalMeta.PushBackNamed(restxml.UnmarshalMetaHandler)
|
||||
svc.Handlers.UnmarshalError.PushBackNamed(restxml.UnmarshalErrorHandler)
|
||||
|
||||
svc.Handlers.BuildStream.PushBackNamed(restxml.BuildHandler)
|
||||
svc.Handlers.UnmarshalStream.PushBackNamed(restxml.UnmarshalHandler)
|
||||
|
||||
// Run custom client initialization if present
|
||||
|
||||
13
vendor/github.com/klauspost/compress/huff0/bitwriter.go
generated
vendored
13
vendor/github.com/klauspost/compress/huff0/bitwriter.go
generated
vendored
@@ -38,7 +38,7 @@ func (b *bitWriter) addBits16Clean(value uint16, bits uint8) {
|
||||
b.nBits += bits
|
||||
}
|
||||
|
||||
// addBits16Clean will add up to 16 bits. value may not contain more set bits than indicated.
|
||||
// encSymbol will add up to 16 bits. value may not contain more set bits than indicated.
|
||||
// It will not check if there is space for them, so the caller must ensure that it has flushed recently.
|
||||
func (b *bitWriter) encSymbol(ct cTable, symbol byte) {
|
||||
enc := ct[symbol]
|
||||
@@ -46,6 +46,17 @@ func (b *bitWriter) encSymbol(ct cTable, symbol byte) {
|
||||
b.nBits += enc.nBits
|
||||
}
|
||||
|
||||
// encTwoSymbols will add up to 32 bits. value may not contain more set bits than indicated.
|
||||
// It will not check if there is space for them, so the caller must ensure that it has flushed recently.
|
||||
func (b *bitWriter) encTwoSymbols(ct cTable, av, bv byte) {
|
||||
encA := ct[av]
|
||||
encB := ct[bv]
|
||||
sh := b.nBits & 63
|
||||
combined := uint64(encA.val) | (uint64(encB.val) << (encA.nBits & 63))
|
||||
b.bitContainer |= combined << sh
|
||||
b.nBits += encA.nBits + encB.nBits
|
||||
}
|
||||
|
||||
// addBits16ZeroNC will add up to 16 bits.
|
||||
// It will not check if there is space for them,
|
||||
// so the caller must ensure that it has flushed recently.
|
||||
|
||||
70
vendor/github.com/klauspost/compress/huff0/compress.go
generated
vendored
70
vendor/github.com/klauspost/compress/huff0/compress.go
generated
vendored
@@ -80,9 +80,12 @@ func compress(in []byte, s *Scratch, compressor func(src []byte) ([]byte, error)
|
||||
|
||||
if s.Reuse == ReusePolicyPrefer && canReuse {
|
||||
keepTable := s.cTable
|
||||
keepTL := s.actualTableLog
|
||||
s.cTable = s.prevTable
|
||||
s.actualTableLog = s.prevTableLog
|
||||
s.Out, err = compressor(in)
|
||||
s.cTable = keepTable
|
||||
s.actualTableLog = keepTL
|
||||
if err == nil && len(s.Out) < wantSize {
|
||||
s.OutData = s.Out
|
||||
return s.Out, true, nil
|
||||
@@ -92,7 +95,6 @@ func compress(in []byte, s *Scratch, compressor func(src []byte) ([]byte, error)
|
||||
}
|
||||
|
||||
// Calculate new table.
|
||||
s.optimalTableLog()
|
||||
err = s.buildCTable()
|
||||
if err != nil {
|
||||
return nil, false, err
|
||||
@@ -109,9 +111,15 @@ func compress(in []byte, s *Scratch, compressor func(src []byte) ([]byte, error)
|
||||
if oldSize <= hSize+newSize || hSize+12 >= wantSize {
|
||||
// Retain cTable even if we re-use.
|
||||
keepTable := s.cTable
|
||||
keepTL := s.actualTableLog
|
||||
|
||||
s.cTable = s.prevTable
|
||||
s.actualTableLog = s.prevTableLog
|
||||
s.Out, err = compressor(in)
|
||||
|
||||
// Restore ctable.
|
||||
s.cTable = keepTable
|
||||
s.actualTableLog = keepTL
|
||||
if err != nil {
|
||||
return nil, false, err
|
||||
}
|
||||
@@ -142,7 +150,7 @@ func compress(in []byte, s *Scratch, compressor func(src []byte) ([]byte, error)
|
||||
return nil, false, ErrIncompressible
|
||||
}
|
||||
// Move current table into previous.
|
||||
s.prevTable, s.cTable = s.cTable, s.prevTable[:0]
|
||||
s.prevTable, s.prevTableLog, s.cTable = s.cTable, s.actualTableLog, s.prevTable[:0]
|
||||
s.OutData = s.Out[len(s.OutTable):]
|
||||
return s.Out, false, nil
|
||||
}
|
||||
@@ -163,28 +171,23 @@ func (s *Scratch) compress1xDo(dst, src []byte) ([]byte, error) {
|
||||
for i := len(src) & 3; i > 0; i-- {
|
||||
bw.encSymbol(cTable, src[n+i-1])
|
||||
}
|
||||
n -= 4
|
||||
if s.actualTableLog <= 8 {
|
||||
n -= 4
|
||||
for ; n >= 0; n -= 4 {
|
||||
tmp := src[n : n+4]
|
||||
// tmp should be len 4
|
||||
bw.flush32()
|
||||
bw.encSymbol(cTable, tmp[3])
|
||||
bw.encSymbol(cTable, tmp[2])
|
||||
bw.encSymbol(cTable, tmp[1])
|
||||
bw.encSymbol(cTable, tmp[0])
|
||||
bw.encTwoSymbols(cTable, tmp[3], tmp[2])
|
||||
bw.encTwoSymbols(cTable, tmp[1], tmp[0])
|
||||
}
|
||||
} else {
|
||||
n -= 4
|
||||
for ; n >= 0; n -= 4 {
|
||||
tmp := src[n : n+4]
|
||||
// tmp should be len 4
|
||||
bw.flush32()
|
||||
bw.encSymbol(cTable, tmp[3])
|
||||
bw.encSymbol(cTable, tmp[2])
|
||||
bw.encTwoSymbols(cTable, tmp[3], tmp[2])
|
||||
bw.flush32()
|
||||
bw.encSymbol(cTable, tmp[1])
|
||||
bw.encSymbol(cTable, tmp[0])
|
||||
bw.encTwoSymbols(cTable, tmp[1], tmp[0])
|
||||
}
|
||||
}
|
||||
err := bw.close()
|
||||
@@ -322,9 +325,26 @@ func (s *Scratch) canUseTable(c cTable) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (s *Scratch) validateTable(c cTable) bool {
|
||||
if len(c) < int(s.symbolLen) {
|
||||
return false
|
||||
}
|
||||
for i, v := range s.count[:s.symbolLen] {
|
||||
if v != 0 {
|
||||
if c[i].nBits == 0 {
|
||||
return false
|
||||
}
|
||||
if c[i].nBits > s.actualTableLog {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// minTableLog provides the minimum logSize to safely represent a distribution.
|
||||
func (s *Scratch) minTableLog() uint8 {
|
||||
minBitsSrc := highBit32(uint32(s.br.remain()-1)) + 1
|
||||
minBitsSrc := highBit32(uint32(s.br.remain())) + 1
|
||||
minBitsSymbols := highBit32(uint32(s.symbolLen-1)) + 2
|
||||
if minBitsSrc < minBitsSymbols {
|
||||
return uint8(minBitsSrc)
|
||||
@@ -336,7 +356,7 @@ func (s *Scratch) minTableLog() uint8 {
|
||||
func (s *Scratch) optimalTableLog() {
|
||||
tableLog := s.TableLog
|
||||
minBits := s.minTableLog()
|
||||
maxBitsSrc := uint8(highBit32(uint32(s.br.remain()-1))) - 2
|
||||
maxBitsSrc := uint8(highBit32(uint32(s.br.remain()-1))) - 1
|
||||
if maxBitsSrc < tableLog {
|
||||
// Accuracy can be reduced
|
||||
tableLog = maxBitsSrc
|
||||
@@ -363,6 +383,7 @@ type cTableEntry struct {
|
||||
const huffNodesMask = huffNodesLen - 1
|
||||
|
||||
func (s *Scratch) buildCTable() error {
|
||||
s.optimalTableLog()
|
||||
s.huffSort()
|
||||
if cap(s.cTable) < maxSymbolValue+1 {
|
||||
s.cTable = make([]cTableEntry, s.symbolLen, maxSymbolValue+1)
|
||||
@@ -439,7 +460,7 @@ func (s *Scratch) buildCTable() error {
|
||||
return fmt.Errorf("internal error: maxNbBits (%d) > tableLogMax (%d)", maxNbBits, tableLogMax)
|
||||
}
|
||||
var nbPerRank [tableLogMax + 1]uint16
|
||||
var valPerRank [tableLogMax + 1]uint16
|
||||
var valPerRank [16]uint16
|
||||
for _, v := range huffNode[:nonNullRank+1] {
|
||||
nbPerRank[v.nbBits]++
|
||||
}
|
||||
@@ -455,16 +476,17 @@ func (s *Scratch) buildCTable() error {
|
||||
}
|
||||
|
||||
// push nbBits per symbol, symbol order
|
||||
// TODO: changed `s.symbolLen` -> `nonNullRank+1` (micro-opt)
|
||||
for _, v := range huffNode[:nonNullRank+1] {
|
||||
s.cTable[v.symbol].nBits = v.nbBits
|
||||
}
|
||||
|
||||
// assign value within rank, symbol order
|
||||
for n, val := range s.cTable[:s.symbolLen] {
|
||||
v := valPerRank[val.nBits]
|
||||
s.cTable[n].val = v
|
||||
valPerRank[val.nBits] = v + 1
|
||||
t := s.cTable[:s.symbolLen]
|
||||
for n, val := range t {
|
||||
nbits := val.nBits & 15
|
||||
v := valPerRank[nbits]
|
||||
t[n].val = v
|
||||
valPerRank[nbits] = v + 1
|
||||
}
|
||||
|
||||
return nil
|
||||
@@ -488,10 +510,12 @@ func (s *Scratch) huffSort() {
|
||||
r := highBit32(v+1) & 31
|
||||
rank[r].base++
|
||||
}
|
||||
for n := 30; n > 0; n-- {
|
||||
// maxBitLength is log2(BlockSizeMax) + 1
|
||||
const maxBitLength = 18 + 1
|
||||
for n := maxBitLength; n > 0; n-- {
|
||||
rank[n-1].base += rank[n].base
|
||||
}
|
||||
for n := range rank[:] {
|
||||
for n := range rank[:maxBitLength] {
|
||||
rank[n].current = rank[n].base
|
||||
}
|
||||
for n, c := range s.count[:s.symbolLen] {
|
||||
@@ -510,7 +534,7 @@ func (s *Scratch) huffSort() {
|
||||
}
|
||||
|
||||
func (s *Scratch) setMaxHeight(lastNonNull int) uint8 {
|
||||
maxNbBits := s.TableLog
|
||||
maxNbBits := s.actualTableLog
|
||||
huffNode := s.nodes[1 : huffNodesLen+1]
|
||||
//huffNode = huffNode[: huffNodesLen]
|
||||
|
||||
|
||||
7
vendor/github.com/klauspost/compress/huff0/huff0.go
generated
vendored
7
vendor/github.com/klauspost/compress/huff0/huff0.go
generated
vendored
@@ -83,7 +83,7 @@ type Scratch struct {
|
||||
MaxSymbolValue uint8
|
||||
|
||||
// TableLog will attempt to override the tablelog for the next block.
|
||||
// Must be <= 11.
|
||||
// Must be <= 11 and >= 5.
|
||||
TableLog uint8
|
||||
|
||||
// Reuse will specify the reuse policy
|
||||
@@ -105,6 +105,7 @@ type Scratch struct {
|
||||
maxCount int // count of the most probable symbol
|
||||
clearCount bool // clear count
|
||||
actualTableLog uint8 // Selected tablelog.
|
||||
prevTableLog uint8 // Tablelog for previous table
|
||||
prevTable cTable // Table used for previous compression.
|
||||
cTable cTable // compression table
|
||||
dt dTable // decompression table
|
||||
@@ -127,8 +128,8 @@ func (s *Scratch) prepare(in []byte) (*Scratch, error) {
|
||||
if s.TableLog == 0 {
|
||||
s.TableLog = tableLogDefault
|
||||
}
|
||||
if s.TableLog > tableLogMax {
|
||||
return nil, fmt.Errorf("tableLog (%d) > maxTableLog (%d)", s.TableLog, tableLogMax)
|
||||
if s.TableLog > tableLogMax || s.TableLog < minTablelog {
|
||||
return nil, fmt.Errorf(" invalid tableLog %d (%d -> %d)", s.TableLog, minTablelog, tableLogMax)
|
||||
}
|
||||
if s.MaxDecodedSize <= 0 || s.MaxDecodedSize > BlockSizeMax {
|
||||
s.MaxDecodedSize = BlockSizeMax
|
||||
|
||||
4
vendor/github.com/klauspost/compress/zstd/README.md
generated
vendored
4
vendor/github.com/klauspost/compress/zstd/README.md
generated
vendored
@@ -36,7 +36,7 @@ so as always, testing is recommended.
|
||||
For now, a high speed (fastest) and medium-fast (default) compressor has been implemented.
|
||||
|
||||
The "Fastest" compression ratio is roughly equivalent to zstd level 1.
|
||||
The "Default" compression ration is roughly equivalent to zstd level 3 (default).
|
||||
The "Default" compression ratio is roughly equivalent to zstd level 3 (default).
|
||||
|
||||
In terms of speed, it is typically 2x as fast as the stdlib deflate/gzip in its fastest mode.
|
||||
The compression ratio compared to stdlib is around level 3, but usually 3x as fast.
|
||||
@@ -390,4 +390,4 @@ For sending files for reproducing errors use a service like [goobox](https://goo
|
||||
|
||||
For general feedback and experience reports, feel free to open an issue or write me on [Twitter](https://twitter.com/sh0dan).
|
||||
|
||||
This package includes the excellent [`github.com/cespare/xxhash`](https://github.com/cespare/xxhash) package Copyright (c) 2016 Caleb Spare.
|
||||
This package includes the excellent [`github.com/cespare/xxhash`](https://github.com/cespare/xxhash) package Copyright (c) 2016 Caleb Spare.
|
||||
|
||||
33
vendor/github.com/klauspost/compress/zstd/blockenc.go
generated
vendored
33
vendor/github.com/klauspost/compress/zstd/blockenc.go
generated
vendored
@@ -299,6 +299,20 @@ func (b *blockEnc) encodeRaw(a []byte) {
|
||||
}
|
||||
}
|
||||
|
||||
// encodeRaw can be used to set the output to a raw representation of supplied bytes.
|
||||
func (b *blockEnc) encodeRawTo(dst, src []byte) []byte {
|
||||
var bh blockHeader
|
||||
bh.setLast(b.last)
|
||||
bh.setSize(uint32(len(src)))
|
||||
bh.setType(blockTypeRaw)
|
||||
dst = bh.appendTo(dst)
|
||||
dst = append(dst, src...)
|
||||
if debug {
|
||||
println("Adding RAW block, length", len(src))
|
||||
}
|
||||
return dst
|
||||
}
|
||||
|
||||
// encodeLits can be used if the block is only litLen.
|
||||
func (b *blockEnc) encodeLits(raw bool) error {
|
||||
var bh blockHeader
|
||||
@@ -324,18 +338,10 @@ func (b *blockEnc) encodeLits(raw bool) error {
|
||||
if len(b.literals) >= 1024 {
|
||||
// Use 4 Streams.
|
||||
out, reUsed, err = huff0.Compress4X(b.literals, b.litEnc)
|
||||
if len(out) > len(b.literals)-len(b.literals)>>4 {
|
||||
// Bail out of compression is too little.
|
||||
err = huff0.ErrIncompressible
|
||||
}
|
||||
} else if len(b.literals) > 32 {
|
||||
// Use 1 stream
|
||||
single = true
|
||||
out, reUsed, err = huff0.Compress1X(b.literals, b.litEnc)
|
||||
if len(out) > len(b.literals)-len(b.literals)>>4 {
|
||||
// Bail out of compression is too little.
|
||||
err = huff0.ErrIncompressible
|
||||
}
|
||||
} else {
|
||||
err = huff0.ErrIncompressible
|
||||
}
|
||||
@@ -437,7 +443,7 @@ func fuzzFseEncoder(data []byte) int {
|
||||
return 1
|
||||
}
|
||||
|
||||
// encode will encode the block and put the output in b.output.
|
||||
// encode will encode the block and append the output in b.output.
|
||||
func (b *blockEnc) encode(raw bool) error {
|
||||
if len(b.sequences) == 0 {
|
||||
return b.encodeLits(raw)
|
||||
@@ -451,6 +457,8 @@ func (b *blockEnc) encode(raw bool) error {
|
||||
var lh literalsHeader
|
||||
bh.setLast(b.last)
|
||||
bh.setType(blockTypeCompressed)
|
||||
// Store offset of the block header. Needed when we know the size.
|
||||
bhOffset := len(b.output)
|
||||
b.output = bh.appendTo(b.output)
|
||||
|
||||
var (
|
||||
@@ -468,6 +476,7 @@ func (b *blockEnc) encode(raw bool) error {
|
||||
} else {
|
||||
err = huff0.ErrIncompressible
|
||||
}
|
||||
|
||||
switch err {
|
||||
case huff0.ErrIncompressible:
|
||||
lh.setType(literalsBlockRaw)
|
||||
@@ -735,18 +744,18 @@ func (b *blockEnc) encode(raw bool) error {
|
||||
}
|
||||
b.output = wr.out
|
||||
|
||||
if len(b.output)-3 >= b.size {
|
||||
if len(b.output)-3-bhOffset >= b.size {
|
||||
// Maybe even add a bigger margin.
|
||||
b.litEnc.Reuse = huff0.ReusePolicyNone
|
||||
return errIncompressible
|
||||
}
|
||||
|
||||
// Size is output minus block header.
|
||||
bh.setSize(uint32(len(b.output)) - 3)
|
||||
bh.setSize(uint32(len(b.output)-bhOffset) - 3)
|
||||
if debug {
|
||||
println("Rewriting block header", bh)
|
||||
}
|
||||
_ = bh.appendTo(b.output[:0])
|
||||
_ = bh.appendTo(b.output[bhOffset:bhOffset])
|
||||
b.coders.setPrev(llEnc, mlEnc, ofEnc)
|
||||
return nil
|
||||
}
|
||||
|
||||
29
vendor/github.com/klauspost/compress/zstd/decoder.go
generated
vendored
29
vendor/github.com/klauspost/compress/zstd/decoder.go
generated
vendored
@@ -388,6 +388,35 @@ func (d *Decoder) Close() {
|
||||
d.current.err = ErrDecoderClosed
|
||||
}
|
||||
|
||||
// IOReadCloser returns the decoder as an io.ReadCloser for convenience.
|
||||
// Any changes to the decoder will be reflected, so the returned ReadCloser
|
||||
// can be reused along with the decoder.
|
||||
// io.WriterTo is also supported by the returned ReadCloser.
|
||||
func (d *Decoder) IOReadCloser() io.ReadCloser {
|
||||
return closeWrapper{d: d}
|
||||
}
|
||||
|
||||
// closeWrapper wraps a function call as a closer.
|
||||
type closeWrapper struct {
|
||||
d *Decoder
|
||||
}
|
||||
|
||||
// WriteTo forwards WriteTo calls to the decoder.
|
||||
func (c closeWrapper) WriteTo(w io.Writer) (n int64, err error) {
|
||||
return c.d.WriteTo(w)
|
||||
}
|
||||
|
||||
// Read forwards read calls to the decoder.
|
||||
func (c closeWrapper) Read(p []byte) (n int, err error) {
|
||||
return c.d.Read(p)
|
||||
}
|
||||
|
||||
// Close closes the decoder.
|
||||
func (c closeWrapper) Close() error {
|
||||
c.d.Close()
|
||||
return nil
|
||||
}
|
||||
|
||||
type decodeOutput struct {
|
||||
d *blockDec
|
||||
b []byte
|
||||
|
||||
313
vendor/github.com/klauspost/compress/zstd/enc_dfast.go
generated
vendored
313
vendor/github.com/klauspost/compress/zstd/enc_dfast.go
generated
vendored
@@ -411,3 +411,316 @@ encodeLoop:
|
||||
println("returning, recent offsets:", blk.recentOffsets, "extra literals:", blk.extraLits)
|
||||
}
|
||||
}
|
||||
|
||||
// EncodeNoHist will encode a block with no history and no following blocks.
|
||||
// Most notable difference is that src will not be copied for history and
|
||||
// we do not need to check for max match length.
|
||||
func (e *doubleFastEncoder) EncodeNoHist(blk *blockEnc, src []byte) {
|
||||
const (
|
||||
// Input margin is the number of bytes we read (8)
|
||||
// and the maximum we will read ahead (2)
|
||||
inputMargin = 8 + 2
|
||||
minNonLiteralBlockSize = 16
|
||||
)
|
||||
|
||||
// Protect against e.cur wraparound.
|
||||
if e.cur > (1<<30)+e.maxMatchOff {
|
||||
for i := range e.table[:] {
|
||||
e.table[i] = tableEntry{}
|
||||
}
|
||||
for i := range e.longTable[:] {
|
||||
e.longTable[i] = tableEntry{}
|
||||
}
|
||||
e.cur = e.maxMatchOff
|
||||
}
|
||||
|
||||
s := int32(0)
|
||||
blk.size = len(src)
|
||||
if len(src) < minNonLiteralBlockSize {
|
||||
blk.extraLits = len(src)
|
||||
blk.literals = blk.literals[:len(src)]
|
||||
copy(blk.literals, src)
|
||||
return
|
||||
}
|
||||
|
||||
// Override src
|
||||
sLimit := int32(len(src)) - inputMargin
|
||||
// stepSize is the number of bytes to skip on every main loop iteration.
|
||||
// It should be >= 1.
|
||||
stepSize := int32(e.o.targetLength)
|
||||
if stepSize == 0 {
|
||||
stepSize++
|
||||
}
|
||||
|
||||
const kSearchStrength = 8
|
||||
|
||||
// nextEmit is where in src the next emitLiteral should start from.
|
||||
nextEmit := s
|
||||
cv := load6432(src, s)
|
||||
|
||||
// Relative offsets
|
||||
offset1 := int32(blk.recentOffsets[0])
|
||||
offset2 := int32(blk.recentOffsets[1])
|
||||
|
||||
addLiterals := func(s *seq, until int32) {
|
||||
if until == nextEmit {
|
||||
return
|
||||
}
|
||||
blk.literals = append(blk.literals, src[nextEmit:until]...)
|
||||
s.litLen = uint32(until - nextEmit)
|
||||
}
|
||||
if debug {
|
||||
println("recent offsets:", blk.recentOffsets)
|
||||
}
|
||||
|
||||
encodeLoop:
|
||||
for {
|
||||
var t int32
|
||||
for {
|
||||
|
||||
nextHashS := hash5(cv, dFastShortTableBits)
|
||||
nextHashL := hash8(cv, dFastLongTableBits)
|
||||
candidateL := e.longTable[nextHashL]
|
||||
candidateS := e.table[nextHashS]
|
||||
|
||||
const repOff = 1
|
||||
repIndex := s - offset1 + repOff
|
||||
entry := tableEntry{offset: s + e.cur, val: uint32(cv)}
|
||||
e.longTable[nextHashL] = entry
|
||||
e.table[nextHashS] = entry
|
||||
|
||||
if len(blk.sequences) > 2 {
|
||||
if load3232(src, repIndex) == uint32(cv>>(repOff*8)) {
|
||||
// Consider history as well.
|
||||
var seq seq
|
||||
//length := 4 + e.matchlen(s+4+repOff, repIndex+4, src)
|
||||
length := 4 + int32(matchLen(src[s+4+repOff:], src[repIndex+4:]))
|
||||
|
||||
seq.matchLen = uint32(length - zstdMinMatch)
|
||||
|
||||
// We might be able to match backwards.
|
||||
// Extend as long as we can.
|
||||
start := s + repOff
|
||||
// We end the search early, so we don't risk 0 literals
|
||||
// and have to do special offset treatment.
|
||||
startLimit := nextEmit + 1
|
||||
|
||||
tMin := s - e.maxMatchOff
|
||||
if tMin < 0 {
|
||||
tMin = 0
|
||||
}
|
||||
for repIndex > tMin && start > startLimit && src[repIndex-1] == src[start-1] {
|
||||
repIndex--
|
||||
start--
|
||||
seq.matchLen++
|
||||
}
|
||||
addLiterals(&seq, start)
|
||||
|
||||
// rep 0
|
||||
seq.offset = 1
|
||||
if debugSequences {
|
||||
println("repeat sequence", seq, "next s:", s)
|
||||
}
|
||||
blk.sequences = append(blk.sequences, seq)
|
||||
s += length + repOff
|
||||
nextEmit = s
|
||||
if s >= sLimit {
|
||||
if debug {
|
||||
println("repeat ended", s, length)
|
||||
|
||||
}
|
||||
break encodeLoop
|
||||
}
|
||||
cv = load6432(src, s)
|
||||
continue
|
||||
}
|
||||
}
|
||||
// Find the offsets of our two matches.
|
||||
coffsetL := s - (candidateL.offset - e.cur)
|
||||
coffsetS := s - (candidateS.offset - e.cur)
|
||||
|
||||
// Check if we have a long match.
|
||||
if coffsetL < e.maxMatchOff && uint32(cv) == candidateL.val {
|
||||
// Found a long match, likely at least 8 bytes.
|
||||
// Reference encoder checks all 8 bytes, we only check 4,
|
||||
// but the likelihood of both the first 4 bytes and the hash matching should be enough.
|
||||
t = candidateL.offset - e.cur
|
||||
if debug && s <= t {
|
||||
panic("s <= t")
|
||||
}
|
||||
if debug && s-t > e.maxMatchOff {
|
||||
panic("s - t >e.maxMatchOff")
|
||||
}
|
||||
if debugMatches {
|
||||
println("long match")
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
// Check if we have a short match.
|
||||
if coffsetS < e.maxMatchOff && uint32(cv) == candidateS.val {
|
||||
// found a regular match
|
||||
// See if we can find a long match at s+1
|
||||
const checkAt = 1
|
||||
cv := load6432(src, s+checkAt)
|
||||
nextHashL = hash8(cv, dFastLongTableBits)
|
||||
candidateL = e.longTable[nextHashL]
|
||||
coffsetL = s - (candidateL.offset - e.cur) + checkAt
|
||||
|
||||
// We can store it, since we have at least a 4 byte match.
|
||||
e.longTable[nextHashL] = tableEntry{offset: s + checkAt + e.cur, val: uint32(cv)}
|
||||
if coffsetL < e.maxMatchOff && uint32(cv) == candidateL.val {
|
||||
// Found a long match, likely at least 8 bytes.
|
||||
// Reference encoder checks all 8 bytes, we only check 4,
|
||||
// but the likelihood of both the first 4 bytes and the hash matching should be enough.
|
||||
t = candidateL.offset - e.cur
|
||||
s += checkAt
|
||||
if debugMatches {
|
||||
println("long match (after short)")
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
t = candidateS.offset - e.cur
|
||||
if debug && s <= t {
|
||||
panic("s <= t")
|
||||
}
|
||||
if debug && s-t > e.maxMatchOff {
|
||||
panic("s - t >e.maxMatchOff")
|
||||
}
|
||||
if debug && t < 0 {
|
||||
panic("t<0")
|
||||
}
|
||||
if debugMatches {
|
||||
println("short match")
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
// No match found, move forward in input.
|
||||
s += stepSize + ((s - nextEmit) >> (kSearchStrength - 1))
|
||||
if s >= sLimit {
|
||||
break encodeLoop
|
||||
}
|
||||
cv = load6432(src, s)
|
||||
}
|
||||
|
||||
// A 4-byte match has been found. Update recent offsets.
|
||||
// We'll later see if more than 4 bytes.
|
||||
offset2 = offset1
|
||||
offset1 = s - t
|
||||
|
||||
if debug && s <= t {
|
||||
panic("s <= t")
|
||||
}
|
||||
|
||||
// Extend the 4-byte match as long as possible.
|
||||
//l := e.matchlen(s+4, t+4, src) + 4
|
||||
l := int32(matchLen(src[s+4:], src[t+4:])) + 4
|
||||
|
||||
// Extend backwards
|
||||
tMin := s - e.maxMatchOff
|
||||
if tMin < 0 {
|
||||
tMin = 0
|
||||
}
|
||||
for t > tMin && s > nextEmit && src[t-1] == src[s-1] {
|
||||
s--
|
||||
t--
|
||||
l++
|
||||
}
|
||||
|
||||
// Write our sequence
|
||||
var seq seq
|
||||
seq.litLen = uint32(s - nextEmit)
|
||||
seq.matchLen = uint32(l - zstdMinMatch)
|
||||
if seq.litLen > 0 {
|
||||
blk.literals = append(blk.literals, src[nextEmit:s]...)
|
||||
}
|
||||
seq.offset = uint32(s-t) + 3
|
||||
s += l
|
||||
if debugSequences {
|
||||
println("sequence", seq, "next s:", s)
|
||||
}
|
||||
blk.sequences = append(blk.sequences, seq)
|
||||
nextEmit = s
|
||||
if s >= sLimit {
|
||||
break encodeLoop
|
||||
}
|
||||
|
||||
// Index match start+1 (long) and start+2 (short)
|
||||
index0 := s - l + 1
|
||||
// Index match end-2 (long) and end-1 (short)
|
||||
index1 := s - 2
|
||||
|
||||
cv0 := load6432(src, index0)
|
||||
cv1 := load6432(src, index1)
|
||||
te0 := tableEntry{offset: index0 + e.cur, val: uint32(cv0)}
|
||||
te1 := tableEntry{offset: index1 + e.cur, val: uint32(cv1)}
|
||||
e.longTable[hash8(cv0, dFastLongTableBits)] = te0
|
||||
e.longTable[hash8(cv1, dFastLongTableBits)] = te1
|
||||
cv0 >>= 8
|
||||
cv1 >>= 8
|
||||
te0.offset++
|
||||
te1.offset++
|
||||
te0.val = uint32(cv0)
|
||||
te1.val = uint32(cv1)
|
||||
e.table[hash5(cv0, dFastShortTableBits)] = te0
|
||||
e.table[hash5(cv1, dFastShortTableBits)] = te1
|
||||
|
||||
cv = load6432(src, s)
|
||||
|
||||
if len(blk.sequences) <= 2 {
|
||||
continue
|
||||
}
|
||||
|
||||
// Check offset 2
|
||||
for {
|
||||
o2 := s - offset2
|
||||
if load3232(src, o2) != uint32(cv) {
|
||||
// Do regular search
|
||||
break
|
||||
}
|
||||
|
||||
// Store this, since we have it.
|
||||
nextHashS := hash5(cv1>>8, dFastShortTableBits)
|
||||
nextHashL := hash8(cv, dFastLongTableBits)
|
||||
|
||||
// We have at least 4 byte match.
|
||||
// No need to check backwards. We come straight from a match
|
||||
//l := 4 + e.matchlen(s+4, o2+4, src)
|
||||
l := 4 + int32(matchLen(src[s+4:], src[o2+4:]))
|
||||
|
||||
entry := tableEntry{offset: s + e.cur, val: uint32(cv)}
|
||||
e.longTable[nextHashL] = entry
|
||||
e.table[nextHashS] = entry
|
||||
seq.matchLen = uint32(l) - zstdMinMatch
|
||||
seq.litLen = 0
|
||||
|
||||
// Since litlen is always 0, this is offset 1.
|
||||
seq.offset = 1
|
||||
s += l
|
||||
nextEmit = s
|
||||
if debugSequences {
|
||||
println("sequence", seq, "next s:", s)
|
||||
}
|
||||
blk.sequences = append(blk.sequences, seq)
|
||||
|
||||
// Swap offset 1 and 2.
|
||||
offset1, offset2 = offset2, offset1
|
||||
if s >= sLimit {
|
||||
// Finished
|
||||
break encodeLoop
|
||||
}
|
||||
cv = load6432(src, s)
|
||||
}
|
||||
}
|
||||
|
||||
if int(nextEmit) < len(src) {
|
||||
blk.literals = append(blk.literals, src[nextEmit:]...)
|
||||
blk.extraLits = len(src) - int(nextEmit)
|
||||
}
|
||||
if debug {
|
||||
println("returning, recent offsets:", blk.recentOffsets, "extra literals:", blk.extraLits)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
245
vendor/github.com/klauspost/compress/zstd/enc_fast.go
generated
vendored
245
vendor/github.com/klauspost/compress/zstd/enc_fast.go
generated
vendored
@@ -329,6 +329,246 @@ encodeLoop:
|
||||
}
|
||||
}
|
||||
|
||||
// EncodeNoHist will encode a block with no history and no following blocks.
|
||||
// Most notable difference is that src will not be copied for history and
|
||||
// we do not need to check for max match length.
|
||||
func (e *fastEncoder) EncodeNoHist(blk *blockEnc, src []byte) {
|
||||
const (
|
||||
inputMargin = 8
|
||||
minNonLiteralBlockSize = 1 + 1 + inputMargin
|
||||
)
|
||||
if debug {
|
||||
if len(src) > maxBlockSize {
|
||||
panic("src too big")
|
||||
}
|
||||
}
|
||||
// Protect against e.cur wraparound.
|
||||
if e.cur > (1<<30)+e.maxMatchOff {
|
||||
for i := range e.table[:] {
|
||||
e.table[i] = tableEntry{}
|
||||
}
|
||||
e.cur = e.maxMatchOff
|
||||
}
|
||||
|
||||
s := int32(0)
|
||||
blk.size = len(src)
|
||||
if len(src) < minNonLiteralBlockSize {
|
||||
blk.extraLits = len(src)
|
||||
blk.literals = blk.literals[:len(src)]
|
||||
copy(blk.literals, src)
|
||||
return
|
||||
}
|
||||
|
||||
sLimit := int32(len(src)) - inputMargin
|
||||
// stepSize is the number of bytes to skip on every main loop iteration.
|
||||
// It should be >= 2.
|
||||
const stepSize = 2
|
||||
|
||||
// TEMPLATE
|
||||
const hashLog = tableBits
|
||||
// seems global, but would be nice to tweak.
|
||||
const kSearchStrength = 8
|
||||
|
||||
// nextEmit is where in src the next emitLiteral should start from.
|
||||
nextEmit := s
|
||||
cv := load6432(src, s)
|
||||
|
||||
// Relative offsets
|
||||
offset1 := int32(blk.recentOffsets[0])
|
||||
offset2 := int32(blk.recentOffsets[1])
|
||||
|
||||
addLiterals := func(s *seq, until int32) {
|
||||
if until == nextEmit {
|
||||
return
|
||||
}
|
||||
blk.literals = append(blk.literals, src[nextEmit:until]...)
|
||||
s.litLen = uint32(until - nextEmit)
|
||||
}
|
||||
if debug {
|
||||
println("recent offsets:", blk.recentOffsets)
|
||||
}
|
||||
|
||||
encodeLoop:
|
||||
for {
|
||||
// t will contain the match offset when we find one.
|
||||
// When existing the search loop, we have already checked 4 bytes.
|
||||
var t int32
|
||||
|
||||
// We will not use repeat offsets across blocks.
|
||||
// By not using them for the first 3 matches
|
||||
|
||||
for {
|
||||
nextHash := hash6(cv, hashLog)
|
||||
nextHash2 := hash6(cv>>8, hashLog)
|
||||
candidate := e.table[nextHash]
|
||||
candidate2 := e.table[nextHash2]
|
||||
repIndex := s - offset1 + 2
|
||||
|
||||
e.table[nextHash] = tableEntry{offset: s + e.cur, val: uint32(cv)}
|
||||
e.table[nextHash2] = tableEntry{offset: s + e.cur + 1, val: uint32(cv >> 8)}
|
||||
|
||||
if len(blk.sequences) > 2 && load3232(src, repIndex) == uint32(cv>>16) {
|
||||
// Consider history as well.
|
||||
var seq seq
|
||||
// lenght := 4 + e.matchlen(s+6, repIndex+4, src)
|
||||
lenght := 4 + int32(matchLen(src[s+6:], src[repIndex+4:]))
|
||||
|
||||
seq.matchLen = uint32(lenght - zstdMinMatch)
|
||||
|
||||
// We might be able to match backwards.
|
||||
// Extend as long as we can.
|
||||
start := s + 2
|
||||
// We end the search early, so we don't risk 0 literals
|
||||
// and have to do special offset treatment.
|
||||
startLimit := nextEmit + 1
|
||||
|
||||
sMin := s - e.maxMatchOff
|
||||
if sMin < 0 {
|
||||
sMin = 0
|
||||
}
|
||||
for repIndex > sMin && start > startLimit && src[repIndex-1] == src[start-1] {
|
||||
repIndex--
|
||||
start--
|
||||
seq.matchLen++
|
||||
}
|
||||
addLiterals(&seq, start)
|
||||
|
||||
// rep 0
|
||||
seq.offset = 1
|
||||
if debugSequences {
|
||||
println("repeat sequence", seq, "next s:", s)
|
||||
}
|
||||
blk.sequences = append(blk.sequences, seq)
|
||||
s += lenght + 2
|
||||
nextEmit = s
|
||||
if s >= sLimit {
|
||||
if debug {
|
||||
println("repeat ended", s, lenght)
|
||||
|
||||
}
|
||||
break encodeLoop
|
||||
}
|
||||
cv = load6432(src, s)
|
||||
continue
|
||||
}
|
||||
coffset0 := s - (candidate.offset - e.cur)
|
||||
coffset1 := s - (candidate2.offset - e.cur) + 1
|
||||
if coffset0 < e.maxMatchOff && uint32(cv) == candidate.val {
|
||||
// found a regular match
|
||||
t = candidate.offset - e.cur
|
||||
if debug && s <= t {
|
||||
panic("s <= t")
|
||||
}
|
||||
if debug && s-t > e.maxMatchOff {
|
||||
panic("s - t >e.maxMatchOff")
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
if coffset1 < e.maxMatchOff && uint32(cv>>8) == candidate2.val {
|
||||
// found a regular match
|
||||
t = candidate2.offset - e.cur
|
||||
s++
|
||||
if debug && s <= t {
|
||||
panic("s <= t")
|
||||
}
|
||||
if debug && s-t > e.maxMatchOff {
|
||||
panic("s - t >e.maxMatchOff")
|
||||
}
|
||||
if debug && t < 0 {
|
||||
panic("t<0")
|
||||
}
|
||||
break
|
||||
}
|
||||
s += stepSize + ((s - nextEmit) >> (kSearchStrength - 1))
|
||||
if s >= sLimit {
|
||||
break encodeLoop
|
||||
}
|
||||
cv = load6432(src, s)
|
||||
}
|
||||
// A 4-byte match has been found. We'll later see if more than 4 bytes.
|
||||
offset2 = offset1
|
||||
offset1 = s - t
|
||||
|
||||
if debug && s <= t {
|
||||
panic("s <= t")
|
||||
}
|
||||
|
||||
// Extend the 4-byte match as long as possible.
|
||||
//l := e.matchlenNoHist(s+4, t+4, src) + 4
|
||||
l := int32(matchLen(src[s+4:], src[t+4:])) + 4
|
||||
|
||||
// Extend backwards
|
||||
tMin := s - e.maxMatchOff
|
||||
if tMin < 0 {
|
||||
tMin = 0
|
||||
}
|
||||
for t > tMin && s > nextEmit && src[t-1] == src[s-1] {
|
||||
s--
|
||||
t--
|
||||
l++
|
||||
}
|
||||
|
||||
// Write our sequence.
|
||||
var seq seq
|
||||
seq.litLen = uint32(s - nextEmit)
|
||||
seq.matchLen = uint32(l - zstdMinMatch)
|
||||
if seq.litLen > 0 {
|
||||
blk.literals = append(blk.literals, src[nextEmit:s]...)
|
||||
}
|
||||
// Don't use repeat offsets
|
||||
seq.offset = uint32(s-t) + 3
|
||||
s += l
|
||||
if debugSequences {
|
||||
println("sequence", seq, "next s:", s)
|
||||
}
|
||||
blk.sequences = append(blk.sequences, seq)
|
||||
nextEmit = s
|
||||
if s >= sLimit {
|
||||
break encodeLoop
|
||||
}
|
||||
cv = load6432(src, s)
|
||||
|
||||
// Check offset 2
|
||||
if o2 := s - offset2; len(blk.sequences) > 2 && load3232(src, o2) == uint32(cv) {
|
||||
// We have at least 4 byte match.
|
||||
// No need to check backwards. We come straight from a match
|
||||
//l := 4 + e.matchlenNoHist(s+4, o2+4, src)
|
||||
l := 4 + int32(matchLen(src[s+4:], src[o2+4:]))
|
||||
|
||||
// Store this, since we have it.
|
||||
nextHash := hash6(cv, hashLog)
|
||||
e.table[nextHash] = tableEntry{offset: s + e.cur, val: uint32(cv)}
|
||||
seq.matchLen = uint32(l) - zstdMinMatch
|
||||
seq.litLen = 0
|
||||
// Since litlen is always 0, this is offset 1.
|
||||
seq.offset = 1
|
||||
s += l
|
||||
nextEmit = s
|
||||
if debugSequences {
|
||||
println("sequence", seq, "next s:", s)
|
||||
}
|
||||
blk.sequences = append(blk.sequences, seq)
|
||||
|
||||
// Swap offset 1 and 2.
|
||||
offset1, offset2 = offset2, offset1
|
||||
if s >= sLimit {
|
||||
break encodeLoop
|
||||
}
|
||||
// Prepare next loop.
|
||||
cv = load6432(src, s)
|
||||
}
|
||||
}
|
||||
|
||||
if int(nextEmit) < len(src) {
|
||||
blk.literals = append(blk.literals, src[nextEmit:]...)
|
||||
blk.extraLits = len(src) - int(nextEmit)
|
||||
}
|
||||
if debug {
|
||||
println("returning, recent offsets:", blk.recentOffsets, "extra literals:", blk.extraLits)
|
||||
}
|
||||
}
|
||||
|
||||
func (e *fastEncoder) addBlock(src []byte) int32 {
|
||||
// check if we have space already
|
||||
if len(e.hist)+len(src) > cap(e.hist) {
|
||||
@@ -362,6 +602,11 @@ func (e *fastEncoder) UseBlock(enc *blockEnc) {
|
||||
e.blk = enc
|
||||
}
|
||||
|
||||
func (e *fastEncoder) matchlenNoHist(s, t int32, src []byte) int32 {
|
||||
// Extend the match to be as long as possible.
|
||||
return int32(matchLen(src[s:], src[t:]))
|
||||
}
|
||||
|
||||
func (e *fastEncoder) matchlen(s, t int32, src []byte) int32 {
|
||||
if debug {
|
||||
if s < 0 {
|
||||
|
||||
71
vendor/github.com/klauspost/compress/zstd/encoder.go
generated
vendored
71
vendor/github.com/klauspost/compress/zstd/encoder.go
generated
vendored
@@ -29,6 +29,7 @@ type Encoder struct {
|
||||
|
||||
type encoder interface {
|
||||
Encode(blk *blockEnc, src []byte)
|
||||
EncodeNoHist(blk *blockEnc, src []byte)
|
||||
Block() *blockEnc
|
||||
CRC() *xxhash.Digest
|
||||
AppendCRC([]byte) []byte
|
||||
@@ -433,7 +434,8 @@ func (e *Encoder) EncodeAll(src, dst []byte) []byte {
|
||||
}()
|
||||
enc.Reset()
|
||||
blk := enc.Block()
|
||||
single := len(src) > 1<<20
|
||||
// Use single segments when above minimum window and below 1MB.
|
||||
single := len(src) < 1<<20 && len(src) > MinWindowSize
|
||||
if e.o.single != nil {
|
||||
single = *e.o.single
|
||||
}
|
||||
@@ -454,25 +456,22 @@ func (e *Encoder) EncodeAll(src, dst []byte) []byte {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
for len(src) > 0 {
|
||||
todo := src
|
||||
if len(todo) > e.o.blockSize {
|
||||
todo = todo[:e.o.blockSize]
|
||||
}
|
||||
src = src[len(todo):]
|
||||
if len(src) <= e.o.blockSize && len(src) <= maxBlockSize {
|
||||
// Slightly faster with no history and everything in one block.
|
||||
if e.o.crc {
|
||||
_, _ = enc.CRC().Write(todo)
|
||||
_, _ = enc.CRC().Write(src)
|
||||
}
|
||||
blk.reset(nil)
|
||||
blk.pushOffsets()
|
||||
enc.Encode(blk, todo)
|
||||
if len(src) == 0 {
|
||||
blk.last = true
|
||||
}
|
||||
err := errIncompressible
|
||||
blk.last = true
|
||||
enc.EncodeNoHist(blk, src)
|
||||
|
||||
// If we got the exact same number of literals as input,
|
||||
// assume the literals cannot be compressed.
|
||||
if len(blk.literals) != len(todo) || len(todo) != e.o.blockSize {
|
||||
err := errIncompressible
|
||||
oldout := blk.output
|
||||
if len(blk.literals) != len(src) || len(src) != e.o.blockSize {
|
||||
// Output directly to dst
|
||||
blk.output = dst
|
||||
err = blk.encode(e.o.noEntropy)
|
||||
}
|
||||
|
||||
@@ -481,13 +480,49 @@ func (e *Encoder) EncodeAll(src, dst []byte) []byte {
|
||||
if debug {
|
||||
println("Storing incompressible block as raw")
|
||||
}
|
||||
blk.encodeRaw(todo)
|
||||
blk.popOffsets()
|
||||
dst = blk.encodeRawTo(dst, src)
|
||||
case nil:
|
||||
dst = blk.output
|
||||
default:
|
||||
panic(err)
|
||||
}
|
||||
dst = append(dst, blk.output...)
|
||||
blk.output = oldout
|
||||
} else {
|
||||
for len(src) > 0 {
|
||||
todo := src
|
||||
if len(todo) > e.o.blockSize {
|
||||
todo = todo[:e.o.blockSize]
|
||||
}
|
||||
src = src[len(todo):]
|
||||
if e.o.crc {
|
||||
_, _ = enc.CRC().Write(todo)
|
||||
}
|
||||
blk.reset(nil)
|
||||
blk.pushOffsets()
|
||||
enc.Encode(blk, todo)
|
||||
if len(src) == 0 {
|
||||
blk.last = true
|
||||
}
|
||||
err := errIncompressible
|
||||
// If we got the exact same number of literals as input,
|
||||
// assume the literals cannot be compressed.
|
||||
if len(blk.literals) != len(todo) || len(todo) != e.o.blockSize {
|
||||
err = blk.encode(e.o.noEntropy)
|
||||
}
|
||||
|
||||
switch err {
|
||||
case errIncompressible:
|
||||
if debug {
|
||||
println("Storing incompressible block as raw")
|
||||
}
|
||||
dst = blk.encodeRawTo(dst, todo)
|
||||
blk.popOffsets()
|
||||
case nil:
|
||||
dst = append(dst, blk.output...)
|
||||
default:
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
if e.o.crc {
|
||||
dst = enc.AppendCRC(dst)
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user