From 3ae59274e360c4830af514750ec9899bfb11aa98 Mon Sep 17 00:00:00 2001 From: tidwall Date: Fri, 26 Apr 2019 11:50:49 -0700 Subject: [PATCH] Removed evio option --- Gopkg.lock | 20 - Gopkg.toml | 3 +- cmd/tile38-server/main.go | 14 +- core/options.go | 3 - internal/server/client.go | 17 +- internal/server/server.go | 232 +------- .../kavu/go_reuseport/.circleci/config.yml | 14 - .../github.com/kavu/go_reuseport/.gitignore | 23 - .../github.com/kavu/go_reuseport/.travis.yml | 30 - vendor/github.com/kavu/go_reuseport/LICENSE | 21 - vendor/github.com/kavu/go_reuseport/Makefile | 9 - vendor/github.com/kavu/go_reuseport/README.md | 48 -- vendor/github.com/kavu/go_reuseport/go.mod | 1 - .../github.com/kavu/go_reuseport/reuseport.go | 50 -- .../kavu/go_reuseport/reuseport_bsd.go | 44 -- .../kavu/go_reuseport/reuseport_linux.go | 52 -- .../kavu/go_reuseport/reuseport_windows.go | 19 - vendor/github.com/kavu/go_reuseport/tcp.go | 143 ----- .../github.com/kavu/go_reuseport/tcp_test.go | 218 ------- vendor/github.com/kavu/go_reuseport/test.bash | 22 - vendor/github.com/kavu/go_reuseport/udp.go | 143 ----- .../github.com/kavu/go_reuseport/udp_test.go | 99 ---- vendor/github.com/tidwall/evio/.travis.yml | 2 - vendor/github.com/tidwall/evio/LICENSE | 20 - vendor/github.com/tidwall/evio/README.md | 168 ------ .../tidwall/evio/benchmarks/.gitignore | 2 - .../tidwall/evio/benchmarks/README.md | 27 - .../tidwall/evio/benchmarks/analyze.go | 308 ---------- .../tidwall/evio/benchmarks/bench-echo.sh | 36 -- .../tidwall/evio/benchmarks/bench-http.sh | 37 -- .../tidwall/evio/benchmarks/bench-redis.sh | 43 -- .../tidwall/evio/benchmarks/bench.sh | 15 - .../evio/benchmarks/fasthttp-server/main.go | 32 -- .../evio/benchmarks/net-echo-server/main.go | 47 -- .../evio/benchmarks/net-http-server/main.go | 36 -- .../tidwall/evio/benchmarks/out/echo.png | Bin 13583 -> 0 bytes .../tidwall/evio/benchmarks/out/echo.txt | 34 -- .../tidwall/evio/benchmarks/out/http.png | Bin 15932 -> 0 bytes .../tidwall/evio/benchmarks/out/http.txt | 49 -- .../tidwall/evio/benchmarks/out/redis1.txt | 28 - .../tidwall/evio/benchmarks/out/redis16.txt | 28 - .../tidwall/evio/benchmarks/out/redis8.txt | 28 - .../evio/benchmarks/out/redis_pipeline_1.png | Bin 14936 -> 0 bytes .../evio/benchmarks/out/redis_pipeline_16.png | Bin 16250 -> 0 bytes .../evio/benchmarks/out/redis_pipeline_8.png | Bin 16235 -> 0 bytes vendor/github.com/tidwall/evio/evio.go | 268 --------- vendor/github.com/tidwall/evio/evio_other.go | 41 -- vendor/github.com/tidwall/evio/evio_std.go | 459 --------------- vendor/github.com/tidwall/evio/evio_test.go | 478 ---------------- vendor/github.com/tidwall/evio/evio_unix.go | 534 ------------------ .../tidwall/evio/examples/echo-server/main.go | 59 -- .../tidwall/evio/examples/http-server/main.go | 221 -------- .../evio/examples/redis-server/main.go | 181 ------ .../tidwall/evio/internal/internal_bsd.go | 125 ---- .../tidwall/evio/internal/internal_darwin.go | 20 - .../tidwall/evio/internal/internal_linux.go | 129 ----- .../tidwall/evio/internal/internal_openbsd.go | 11 - .../tidwall/evio/internal/internal_unix.go | 19 - .../tidwall/evio/internal/notequeue.go | 53 -- .../tidwall/evio/internal/socktoaddr.go | 39 -- vendor/github.com/tidwall/evio/logo.png | Bin 25681 -> 0 bytes 61 files changed, 46 insertions(+), 4756 deletions(-) delete mode 100644 vendor/github.com/kavu/go_reuseport/.circleci/config.yml delete mode 100644 vendor/github.com/kavu/go_reuseport/.gitignore delete mode 100644 vendor/github.com/kavu/go_reuseport/.travis.yml delete mode 100644 vendor/github.com/kavu/go_reuseport/LICENSE delete mode 100644 vendor/github.com/kavu/go_reuseport/Makefile delete mode 100644 vendor/github.com/kavu/go_reuseport/README.md delete mode 100644 vendor/github.com/kavu/go_reuseport/go.mod delete mode 100644 vendor/github.com/kavu/go_reuseport/reuseport.go delete mode 100644 vendor/github.com/kavu/go_reuseport/reuseport_bsd.go delete mode 100644 vendor/github.com/kavu/go_reuseport/reuseport_linux.go delete mode 100644 vendor/github.com/kavu/go_reuseport/reuseport_windows.go delete mode 100644 vendor/github.com/kavu/go_reuseport/tcp.go delete mode 100644 vendor/github.com/kavu/go_reuseport/tcp_test.go delete mode 100755 vendor/github.com/kavu/go_reuseport/test.bash delete mode 100644 vendor/github.com/kavu/go_reuseport/udp.go delete mode 100644 vendor/github.com/kavu/go_reuseport/udp_test.go delete mode 100644 vendor/github.com/tidwall/evio/.travis.yml delete mode 100644 vendor/github.com/tidwall/evio/LICENSE delete mode 100644 vendor/github.com/tidwall/evio/README.md delete mode 100644 vendor/github.com/tidwall/evio/benchmarks/.gitignore delete mode 100644 vendor/github.com/tidwall/evio/benchmarks/README.md delete mode 100644 vendor/github.com/tidwall/evio/benchmarks/analyze.go delete mode 100755 vendor/github.com/tidwall/evio/benchmarks/bench-echo.sh delete mode 100755 vendor/github.com/tidwall/evio/benchmarks/bench-http.sh delete mode 100755 vendor/github.com/tidwall/evio/benchmarks/bench-redis.sh delete mode 100755 vendor/github.com/tidwall/evio/benchmarks/bench.sh delete mode 100644 vendor/github.com/tidwall/evio/benchmarks/fasthttp-server/main.go delete mode 100644 vendor/github.com/tidwall/evio/benchmarks/net-echo-server/main.go delete mode 100644 vendor/github.com/tidwall/evio/benchmarks/net-http-server/main.go delete mode 100644 vendor/github.com/tidwall/evio/benchmarks/out/echo.png delete mode 100644 vendor/github.com/tidwall/evio/benchmarks/out/echo.txt delete mode 100644 vendor/github.com/tidwall/evio/benchmarks/out/http.png delete mode 100644 vendor/github.com/tidwall/evio/benchmarks/out/http.txt delete mode 100644 vendor/github.com/tidwall/evio/benchmarks/out/redis1.txt delete mode 100644 vendor/github.com/tidwall/evio/benchmarks/out/redis16.txt delete mode 100644 vendor/github.com/tidwall/evio/benchmarks/out/redis8.txt delete mode 100644 vendor/github.com/tidwall/evio/benchmarks/out/redis_pipeline_1.png delete mode 100644 vendor/github.com/tidwall/evio/benchmarks/out/redis_pipeline_16.png delete mode 100644 vendor/github.com/tidwall/evio/benchmarks/out/redis_pipeline_8.png delete mode 100644 vendor/github.com/tidwall/evio/evio.go delete mode 100644 vendor/github.com/tidwall/evio/evio_other.go delete mode 100644 vendor/github.com/tidwall/evio/evio_std.go delete mode 100644 vendor/github.com/tidwall/evio/evio_test.go delete mode 100644 vendor/github.com/tidwall/evio/evio_unix.go delete mode 100644 vendor/github.com/tidwall/evio/examples/echo-server/main.go delete mode 100644 vendor/github.com/tidwall/evio/examples/http-server/main.go delete mode 100644 vendor/github.com/tidwall/evio/examples/redis-server/main.go delete mode 100644 vendor/github.com/tidwall/evio/internal/internal_bsd.go delete mode 100644 vendor/github.com/tidwall/evio/internal/internal_darwin.go delete mode 100644 vendor/github.com/tidwall/evio/internal/internal_linux.go delete mode 100644 vendor/github.com/tidwall/evio/internal/internal_openbsd.go delete mode 100644 vendor/github.com/tidwall/evio/internal/internal_unix.go delete mode 100644 vendor/github.com/tidwall/evio/internal/notequeue.go delete mode 100644 vendor/github.com/tidwall/evio/internal/socktoaddr.go delete mode 100644 vendor/github.com/tidwall/evio/logo.png diff --git a/Gopkg.lock b/Gopkg.lock index 1113dc2c..a3dcac76 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -128,14 +128,6 @@ pruneopts = "" revision = "c2b33e84" -[[projects]] - digest = "1:be1d3b7623f11b628068933282015f3dbcd522fa8e6b16d2931edffd42ef2c0b" - name = "github.com/kavu/go_reuseport" - packages = ["."] - pruneopts = "" - revision = "ffa96de2479e10ecd06aca8069bf9c55a86701b5" - version = "v1.4.0" - [[projects]] branch = "master" digest = "1:75dddee0eb82002b5aff6937fdf6d544b85322d2414524a521768fe4b4e5ed3d" @@ -228,17 +220,6 @@ revision = "6249481c29c2cd96f53b691b74ac1893f72774c2" version = "v1.1.0" -[[projects]] - digest = "1:91acf4d86b348c1f1832336836035373b047ffcb16a0fde066bd531bbe3452b2" - name = "github.com/tidwall/evio" - packages = [ - ".", - "internal", - ] - pruneopts = "" - revision = "b353be3a765785dafabbb63a7b25aadec3533946" - version = "v1.0.2" - [[projects]] digest = "1:cdab3bce90a53a124ac3982719abde77d779e961d9c180e55c23fb74fc62563a" name = "github.com/tidwall/geojson" @@ -482,7 +463,6 @@ "github.com/tidwall/boxtree/d2", "github.com/tidwall/btree", "github.com/tidwall/buntdb", - "github.com/tidwall/evio", "github.com/tidwall/geojson", "github.com/tidwall/geojson/geo", "github.com/tidwall/geojson/geometry", diff --git a/Gopkg.toml b/Gopkg.toml index d118b3e6..7937a2f5 100644 --- a/Gopkg.toml +++ b/Gopkg.toml @@ -22,8 +22,7 @@ required = [ "github.com/tidwall/lotsa", - "github.com/mmcloughlin/geohash", - "github.com/tidwall/evio" + "github.com/mmcloughlin/geohash" ] [[constraint]] diff --git a/cmd/tile38-server/main.go b/cmd/tile38-server/main.go index 434a552d..f9924c38 100644 --- a/cmd/tile38-server/main.go +++ b/cmd/tile38-server/main.go @@ -101,7 +101,6 @@ Advanced Options: --http-transport yes/no : HTTP transport (default: yes) --protected-mode yes/no : protected mode (default: yes) --threads num : number of network threads (default: num cores) - --evio yes/no : use the evio package (default: no) --nohup : do not exist on SIGHUP Developer Options: @@ -153,6 +152,8 @@ Developer Options: return } + var showEvioDisabled bool + // parse non standard args. nargs := []string{os.Args[0]} for i := 1; i < len(os.Args); i++ { @@ -243,11 +244,8 @@ Developer Options: i++ if i < len(os.Args) { switch strings.ToLower(os.Args[i]) { - case "no": - core.Evio = false - continue - case "yes": - core.Evio = true + case "no", "yes": + showEvioDisabled = true continue } } @@ -408,6 +406,10 @@ Developer Options: if pidferr != nil { log.Warnf("pidfile: %v", pidferr) } + if showEvioDisabled { + // we don't currently support evio in Tile38 + log.Warnf("evio is not currently supported") + } if err := server.Serve(host, port, dir, httpTransport); err != nil { log.Fatal(err) } diff --git a/core/options.go b/core/options.go index 6be8f51d..2b8555be 100644 --- a/core/options.go +++ b/core/options.go @@ -20,6 +20,3 @@ var QueueFileName = "" // NumThreads is the number of network threads to use. var NumThreads int - -// Evio set the networking to use the evio package. -var Evio = false diff --git a/internal/server/client.go b/internal/server/client.go index ab19b2c2..92e7afd1 100644 --- a/internal/server/client.go +++ b/internal/server/client.go @@ -10,20 +10,19 @@ import ( "sync" "time" - "github.com/tidwall/evio" "github.com/tidwall/resp" ) // Client is an remote connection into to Tile38 type Client struct { - id int // unique id - replPort int // the known replication port for follower connections - authd bool // client has been authenticated - outputType Type // Null, JSON, or RESP - remoteAddr string // original remote address - in evio.InputStream // input stream - pr PipelineReader // command reader - out []byte // output write buffer + id int // unique id + replPort int // the known replication port for follower connections + authd bool // client has been authenticated + outputType Type // Null, JSON, or RESP + remoteAddr string // original remote address + in InputStream // input stream + pr PipelineReader // command reader + out []byte // output write buffer goLiveErr error // error type used for going line goLiveMsg *Message // last message for go live diff --git a/internal/server/server.go b/internal/server/server.go index 2091aecf..bf6c8287 100644 --- a/internal/server/server.go +++ b/internal/server/server.go @@ -24,7 +24,6 @@ import ( "github.com/tidwall/boxtree/d2" "github.com/tidwall/buntdb" - "github.com/tidwall/evio" "github.com/tidwall/geojson" "github.com/tidwall/geojson/geometry" "github.com/tidwall/redcon" @@ -39,6 +38,7 @@ import ( ) var errOOM = errors.New("OOM command not allowed when used memory > 'maxmemory'") + func errTimeoutOnCmd(cmd string) error { return fmt.Errorf("timeout not supported for '%s'", cmd) } @@ -284,9 +284,6 @@ func Serve(host string, port int, dir string, http bool) error { }() // Start the network server - if core.Evio { - return server.evioServe() - } return server.netServe() } @@ -304,203 +301,6 @@ func (server *Server) isProtected() bool { return is } -func (server *Server) evioServe() error { - var events evio.Events - if core.NumThreads == 0 { - events.NumLoops = -1 - } else { - events.NumLoops = core.NumThreads - } - events.LoadBalance = evio.LeastConnections - events.Serving = func(eserver evio.Server) (action evio.Action) { - if eserver.NumLoops == 1 { - log.Infof("Running single-threaded") - } else { - log.Infof("Running on %d threads", eserver.NumLoops) - } - for _, addr := range eserver.Addrs { - log.Infof("Ready to accept connections at %s", - addr) - } - return - } - var clientID int64 - events.Opened = func(econn evio.Conn) (out []byte, opts evio.Options, action evio.Action) { - // create the client - client := new(Client) - client.id = int(atomic.AddInt64(&clientID, 1)) - client.opened = time.Now() - client.remoteAddr = econn.RemoteAddr().String() - - // keep track of the client - econn.SetContext(client) - - // add client to server map - server.connsmu.Lock() - server.conns[client.id] = client - server.connsmu.Unlock() - server.statsTotalConns.add(1) - - // set the client keep-alive, if needed - if server.config.keepAlive() > 0 { - opts.TCPKeepAlive = time.Duration(server.config.keepAlive()) * time.Second - } - log.Debugf("Opened connection: %s", client.remoteAddr) - - // check if the connection is protected - if !strings.HasPrefix(client.remoteAddr, "127.0.0.1:") && - !strings.HasPrefix(client.remoteAddr, "[::1]:") { - if server.isProtected() { - // This is a protected server. Only loopback is allowed. - out = append(out, deniedMessage...) - action = evio.Close - return - } - } - return - } - - events.Closed = func(econn evio.Conn, err error) (action evio.Action) { - // load the client - client := econn.Context().(*Client) - - // delete from server map - server.connsmu.Lock() - delete(server.conns, client.id) - server.connsmu.Unlock() - - log.Debugf("Closed connection: %s", client.remoteAddr) - return - } - - events.Data = func(econn evio.Conn, in []byte) (out []byte, action evio.Action) { - // load the client - client := econn.Context().(*Client) - - // read the payload packet from the client input stream. - packet := client.in.Begin(in) - - // load the pipeline reader - pr := &client.pr - rdbuf := bytes.NewBuffer(packet) - pr.rd = rdbuf - pr.wr = client - - msgs, err := pr.ReadMessages() - if err != nil { - log.Error(err) - action = evio.Close - return - } - for _, msg := range msgs { - // Just closing connection if we have deprecated HTTP or WS connection, - // And --http-transport = false - if !server.http && (msg.ConnType == WebSocket || - msg.ConnType == HTTP) { - action = evio.Close - break - } - if msg != nil && msg.Command() != "" { - if client.outputType != Null { - msg.OutputType = client.outputType - } - if msg.Command() == "quit" { - if msg.OutputType == RESP { - io.WriteString(client, "+OK\r\n") - } - action = evio.Close - break - } - - // increment last used - client.mu.Lock() - client.last = time.Now() - client.mu.Unlock() - - // update total command count - server.statsTotalCommands.add(1) - - // handle the command - err := server.handleInputCommand(client, msg) - if err != nil { - if err.Error() == goingLive { - client.goLiveErr = err - client.goLiveMsg = msg - action = evio.Detach - return - } - log.Error(err) - action = evio.Close - return - } - - client.outputType = msg.OutputType - } else { - client.Write([]byte("HTTP/1.1 500 Bad Request\r\nConnection: close\r\n\r\n")) - action = evio.Close - break - } - if msg.ConnType == HTTP || msg.ConnType == WebSocket { - action = evio.Close - break - } - } - - packet = packet[len(packet)-rdbuf.Len():] - client.in.End(packet) - - out = client.out - client.out = nil - return - } - - events.Detached = func(econn evio.Conn, rwc io.ReadWriteCloser) (action evio.Action) { - client := econn.Context().(*Client) - client.conn = rwc - if len(client.out) > 0 { - rwc.Write(client.out) - client.out = nil - } - client.in = evio.InputStream{} - client.pr.rd = rwc - client.pr.wr = rwc - - log.Debugf("Detached connection: %s", client.remoteAddr) - go func() { - defer func() { - // close connection - rwc.Close() - server.connsmu.Lock() - delete(server.conns, client.id) - server.connsmu.Unlock() - log.Debugf("Closed connection: %s", client.remoteAddr) - }() - err := server.goLive( - client.goLiveErr, - &liveConn{econn.RemoteAddr(), rwc}, - &client.pr, - client.goLiveMsg, - client.goLiveMsg.ConnType == WebSocket, - ) - if err != nil { - log.Error(err) - } - }() - return - } - - events.PreWrite = func() { - if atomic.LoadInt32(&server.aofdirty) != 0 { - server.mu.Lock() - defer server.mu.Unlock() - server.flushAOF(false) - atomic.StoreInt32(&server.aofdirty, 1) - } - } - - return evio.Serve(events, fmt.Sprintf("%s:%d", server.host, server.port)) -} - func (server *Server) netServe() error { ln, err := net.Listen("tcp", fmt.Sprintf("%s:%d", server.host, server.port)) if err != nil { @@ -623,7 +423,7 @@ func (server *Server) netServe() error { client.conn.Write(client.out) client.out = nil } - client.in = evio.InputStream{} + client.in = InputStream{} client.pr.rd = rwc client.pr.wr = rwc log.Debugf("Detached connection: %s", client.remoteAddr) @@ -1056,7 +856,7 @@ func (server *Server) handleInputCommand(client *Client, msg *Message) error { if msg.Deadline != nil { if write { res = NOMessage - err = errTimeoutOnCmd(msg.Command()) + err = errTimeoutOnCmd(msg.Command()) return } defer func() { @@ -1639,3 +1439,29 @@ reading: } return &Message{Args: args, ConnType: Native, OutputType: JSON}, nil } + +// InputStream is a helper type for managing input streams from inside +// the Data event. +type InputStream struct{ b []byte } + +// Begin accepts a new packet and returns a working sequence of +// unprocessed bytes. +func (is *InputStream) Begin(packet []byte) (data []byte) { + data = packet + if len(is.b) > 0 { + is.b = append(is.b, data...) + data = is.b + } + return data +} + +// End shifts the stream to match the unprocessed data. +func (is *InputStream) End(data []byte) { + if len(data) > 0 { + if len(data) != len(is.b) { + is.b = append(is.b[:0], data...) + } + } else if len(is.b) > 0 { + is.b = is.b[:0] + } +} diff --git a/vendor/github.com/kavu/go_reuseport/.circleci/config.yml b/vendor/github.com/kavu/go_reuseport/.circleci/config.yml deleted file mode 100644 index ca3688dd..00000000 --- a/vendor/github.com/kavu/go_reuseport/.circleci/config.yml +++ /dev/null @@ -1,14 +0,0 @@ -version: 2 -jobs: - build: - docker: - - image: circleci/golang:1.8 - - working_directory: /go/src/github.com/kavu/go_reuseport - - steps: - - checkout - - run: go get -v -t -d ./... - - run: go test -v -cover ./... - - run: go test -v -cover -race ./... -coverprofile=coverage.txt -covermode=atomic - - run: go test -v -cover -race -benchmem -benchtime=5s -bench=. diff --git a/vendor/github.com/kavu/go_reuseport/.gitignore b/vendor/github.com/kavu/go_reuseport/.gitignore deleted file mode 100644 index 8661ba57..00000000 --- a/vendor/github.com/kavu/go_reuseport/.gitignore +++ /dev/null @@ -1,23 +0,0 @@ -# Compiled Object files, Static and Dynamic libs (Shared Objects) -*.o -*.a -*.so - -# Folders -_obj -_test - -# Architecture specific extensions/prefixes -*.[568vq] -[568vq].out - -*.cgo1.go -*.cgo2.c -_cgo_defun.c -_cgo_gotypes.go -_cgo_export.* - -_testmain.go - -*.exe -.DS_Store diff --git a/vendor/github.com/kavu/go_reuseport/.travis.yml b/vendor/github.com/kavu/go_reuseport/.travis.yml deleted file mode 100644 index e858e343..00000000 --- a/vendor/github.com/kavu/go_reuseport/.travis.yml +++ /dev/null @@ -1,30 +0,0 @@ -dist: trusty -sudo: true - -language: go - -go: - - "1.6" - - "1.7" - - "1.8" - - "1.9" - - "1.10" - - "1.11" - - tip - -os: - - linux - - osx - -before_install: - - uname -a - -script: ./test.bash - -matrix: - allow_failures: - - os: osx - - go: tip - -after_success: - - bash <(curl -s https://codecov.io/bash) diff --git a/vendor/github.com/kavu/go_reuseport/LICENSE b/vendor/github.com/kavu/go_reuseport/LICENSE deleted file mode 100644 index 5f25159a..00000000 --- a/vendor/github.com/kavu/go_reuseport/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2014 Max Riveiro - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. \ No newline at end of file diff --git a/vendor/github.com/kavu/go_reuseport/Makefile b/vendor/github.com/kavu/go_reuseport/Makefile deleted file mode 100644 index 4aa3d2b6..00000000 --- a/vendor/github.com/kavu/go_reuseport/Makefile +++ /dev/null @@ -1,9 +0,0 @@ -lint: - @gometalinter \ - --disable=errcheck \ - --disable=dupl \ - --min-const-length=5 \ - --min-confidence=0.25 \ - --cyclo-over=20 \ - --enable=unused \ - --deadline=100s diff --git a/vendor/github.com/kavu/go_reuseport/README.md b/vendor/github.com/kavu/go_reuseport/README.md deleted file mode 100644 index 9e9726b6..00000000 --- a/vendor/github.com/kavu/go_reuseport/README.md +++ /dev/null @@ -1,48 +0,0 @@ -# GO_REUSEPORT - -[![Build Status](https://travis-ci.org/kavu/go_reuseport.png?branch=master)](https://travis-ci.org/kavu/go_reuseport) -[![codecov](https://codecov.io/gh/kavu/go_reuseport/branch/master/graph/badge.svg)](https://codecov.io/gh/kavu/go_reuseport) -[![GoDoc](https://godoc.org/github.com/kavu/go_reuseport?status.png)](https://godoc.org/github.com/kavu/go_reuseport) - -**GO_REUSEPORT** is a little expirement to create a `net.Listener` that supports [SO_REUSEPORT](http://lwn.net/Articles/542629/) socket option. - -For now, Darwin and Linux (from 3.9) systems are supported. I'll be pleased if you'll test other systems and tell me the results. - documentation on [godoc.org](http://godoc.org/github.com/kavu/go_reuseport "go_reuseport documentation"). - -## Example ## - -```go -package main - -import ( - "fmt" - "html" - "net/http" - "os" - "runtime" - "github.com/kavu/go_reuseport" -) - -func main() { - listener, err := reuseport.Listen("tcp", "localhost:8881") - if err != nil { - panic(err) - } - defer listener.Close() - - server := &http.Server{} - http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { - fmt.Println(os.Getgid()) - fmt.Fprintf(w, "Hello, %q\n", html.EscapeString(r.URL.Path)) - }) - - panic(server.Serve(listener)) -} -``` - -Now you can run several instances of this tiny server without `Address already in use` errors. - -## Thanks - -Inspired by [Artur Siekielski](https://github.com/aartur) [post](http://freeprogrammersblog.vhex.net/post/linux-39-introdued-new-way-of-writing-socket-servers/2) about `SO_REUSEPORT`. - diff --git a/vendor/github.com/kavu/go_reuseport/go.mod b/vendor/github.com/kavu/go_reuseport/go.mod deleted file mode 100644 index 904b42b0..00000000 --- a/vendor/github.com/kavu/go_reuseport/go.mod +++ /dev/null @@ -1 +0,0 @@ -module github.com/kavu/go_reuseport diff --git a/vendor/github.com/kavu/go_reuseport/reuseport.go b/vendor/github.com/kavu/go_reuseport/reuseport.go deleted file mode 100644 index ea4c7c44..00000000 --- a/vendor/github.com/kavu/go_reuseport/reuseport.go +++ /dev/null @@ -1,50 +0,0 @@ -// +build linux darwin dragonfly freebsd netbsd openbsd - -// Copyright (C) 2017 Max Riveiro -// -// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: -// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -// Package reuseport provides a function that returns a net.Listener powered -// by a net.FileListener with a SO_REUSEPORT option set to the socket. -package reuseport - -import ( - "errors" - "fmt" - "net" - "os" - "syscall" -) - -const fileNameTemplate = "reuseport.%d.%s.%s" - -var errUnsupportedProtocol = errors.New("only tcp, tcp4, tcp6, udp, udp4, udp6 are supported") - -// getSockaddr parses protocol and address and returns implementor -// of syscall.Sockaddr: syscall.SockaddrInet4 or syscall.SockaddrInet6. -func getSockaddr(proto, addr string) (sa syscall.Sockaddr, soType int, err error) { - switch proto { - case "tcp", "tcp4", "tcp6": - return getTCPSockaddr(proto, addr) - case "udp", "udp4", "udp6": - return getUDPSockaddr(proto, addr) - default: - return nil, -1, errUnsupportedProtocol - } -} - -func getSocketFileName(proto, addr string) string { - return fmt.Sprintf(fileNameTemplate, os.Getpid(), proto, addr) -} - -// Listen function is an alias for NewReusablePortListener. -func Listen(proto, addr string) (l net.Listener, err error) { - return NewReusablePortListener(proto, addr) -} - -// ListenPacket is an alias for NewReusablePortPacketConn. -func ListenPacket(proto, addr string) (l net.PacketConn, err error) { - return NewReusablePortPacketConn(proto, addr) -} diff --git a/vendor/github.com/kavu/go_reuseport/reuseport_bsd.go b/vendor/github.com/kavu/go_reuseport/reuseport_bsd.go deleted file mode 100644 index 19000e8d..00000000 --- a/vendor/github.com/kavu/go_reuseport/reuseport_bsd.go +++ /dev/null @@ -1,44 +0,0 @@ -// +build darwin dragonfly freebsd netbsd openbsd - -// Copyright (C) 2017 Ma Weiwei, Max Riveiro -// -// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: -// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -package reuseport - -import ( - "runtime" - "syscall" -) - -var reusePort = syscall.SO_REUSEPORT - -func maxListenerBacklog() int { - var ( - n uint32 - err error - ) - - switch runtime.GOOS { - case "darwin", "freebsd": - n, err = syscall.SysctlUint32("kern.ipc.somaxconn") - case "netbsd": - // NOTE: NetBSD has no somaxconn-like kernel state so far - case "openbsd": - n, err = syscall.SysctlUint32("kern.somaxconn") - } - - if n == 0 || err != nil { - return syscall.SOMAXCONN - } - - // FreeBSD stores the backlog in a uint16, as does Linux. - // Assume the other BSDs do too. Truncate number to avoid wrapping. - // See issue 5030. - if n > 1<<16-1 { - n = 1<<16 - 1 - } - return int(n) -} diff --git a/vendor/github.com/kavu/go_reuseport/reuseport_linux.go b/vendor/github.com/kavu/go_reuseport/reuseport_linux.go deleted file mode 100644 index f6f85a49..00000000 --- a/vendor/github.com/kavu/go_reuseport/reuseport_linux.go +++ /dev/null @@ -1,52 +0,0 @@ -// +build linux - -// Copyright (C) 2017 Ma Weiwei, Max Riveiro -// -// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: -// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -package reuseport - -import ( - "bufio" - "os" - "strconv" - "strings" - "syscall" -) - -var reusePort = 0x0F - -func maxListenerBacklog() int { - fd, err := os.Open("/proc/sys/net/core/somaxconn") - if err != nil { - return syscall.SOMAXCONN - } - defer fd.Close() - - rd := bufio.NewReader(fd) - line, err := rd.ReadString('\n') - if err != nil { - return syscall.SOMAXCONN - } - - f := strings.Fields(line) - if len(f) < 1 { - return syscall.SOMAXCONN - } - - n, err := strconv.Atoi(f[0]) - if err != nil || n == 0 { - return syscall.SOMAXCONN - } - - // Linux stores the backlog in a uint16. - // Truncate number to avoid wrapping. - // See issue 5030. - if n > 1<<16-1 { - n = 1<<16 - 1 - } - - return n -} diff --git a/vendor/github.com/kavu/go_reuseport/reuseport_windows.go b/vendor/github.com/kavu/go_reuseport/reuseport_windows.go deleted file mode 100644 index e1e90df6..00000000 --- a/vendor/github.com/kavu/go_reuseport/reuseport_windows.go +++ /dev/null @@ -1,19 +0,0 @@ -// +build windows - -// Copyright (C) 2017 Ma Weiwei, Max Riveiro -// -// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: -// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -package reuseport - -import "net" - -func NewReusablePortListener(proto, addr string) (net.Listener, error) { - return net.Listen(proto, addr) -} - -func NewReusablePortPacketConn(proto, addr string) (net.PacketConn, error) { - return net.ListenPacket(proto, addr) -} diff --git a/vendor/github.com/kavu/go_reuseport/tcp.go b/vendor/github.com/kavu/go_reuseport/tcp.go deleted file mode 100644 index 76540a15..00000000 --- a/vendor/github.com/kavu/go_reuseport/tcp.go +++ /dev/null @@ -1,143 +0,0 @@ -// +build linux darwin dragonfly freebsd netbsd openbsd - -// Copyright (C) 2017 Max Riveiro -// -// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: -// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -package reuseport - -import ( - "errors" - "net" - "os" - "syscall" -) - -var ( - listenerBacklogMaxSize = maxListenerBacklog() - errUnsupportedTCPProtocol = errors.New("only tcp, tcp4, tcp6 are supported") -) - -func getTCPSockaddr(proto, addr string) (sa syscall.Sockaddr, soType int, err error) { - var tcp *net.TCPAddr - - tcp, err = net.ResolveTCPAddr(proto, addr) - if err != nil && tcp.IP != nil { - return nil, -1, err - } - - tcpVersion, err := determineTCPProto(proto, tcp) - if err != nil { - return nil, -1, err - } - - switch tcpVersion { - case "tcp": - return &syscall.SockaddrInet4{Port: tcp.Port}, syscall.AF_INET, nil - case "tcp4": - sa := &syscall.SockaddrInet4{Port: tcp.Port} - - if tcp.IP != nil { - copy(sa.Addr[:], tcp.IP[12:16]) // copy last 4 bytes of slice to array - } - - return sa, syscall.AF_INET, nil - case "tcp6": - sa := &syscall.SockaddrInet6{Port: tcp.Port} - - if tcp.IP != nil { - copy(sa.Addr[:], tcp.IP) // copy all bytes of slice to array - } - - if tcp.Zone != "" { - iface, err := net.InterfaceByName(tcp.Zone) - if err != nil { - return nil, -1, err - } - - sa.ZoneId = uint32(iface.Index) - } - - return sa, syscall.AF_INET6, nil - } - - return nil, -1, errUnsupportedProtocol -} - -func determineTCPProto(proto string, ip *net.TCPAddr) (string, error) { - // If the protocol is set to "tcp", we try to determine the actual protocol - // version from the size of the resolved IP address. Otherwise, we simple use - // the protcol given to us by the caller. - - if ip.IP.To4() != nil { - return "tcp4", nil - } - - if ip.IP.To16() != nil { - return "tcp6", nil - } - - switch proto { - case "tcp", "tcp4", "tcp6": - return proto, nil - } - - return "", errUnsupportedTCPProtocol -} - -// NewReusablePortListener returns net.FileListener that created from -// a file discriptor for a socket with SO_REUSEPORT option. -func NewReusablePortListener(proto, addr string) (l net.Listener, err error) { - var ( - soType, fd int - file *os.File - sockaddr syscall.Sockaddr - ) - - if sockaddr, soType, err = getSockaddr(proto, addr); err != nil { - return nil, err - } - - syscall.ForkLock.RLock() - if fd, err = syscall.Socket(soType, syscall.SOCK_STREAM, syscall.IPPROTO_TCP); err != nil { - syscall.ForkLock.RUnlock() - - return nil, err - } - syscall.ForkLock.RUnlock() - - if err = syscall.SetsockoptInt(fd, syscall.SOL_SOCKET, syscall.SO_REUSEADDR, 1); err != nil { - syscall.Close(fd) - return nil, err - } - - if err = syscall.SetsockoptInt(fd, syscall.SOL_SOCKET, reusePort, 1); err != nil { - syscall.Close(fd) - return nil, err - } - - if err = syscall.Bind(fd, sockaddr); err != nil { - syscall.Close(fd) - return nil, err - } - - // Set backlog size to the maximum - if err = syscall.Listen(fd, listenerBacklogMaxSize); err != nil { - syscall.Close(fd) - return nil, err - } - - file = os.NewFile(uintptr(fd), getSocketFileName(proto, addr)) - if l, err = net.FileListener(file); err != nil { - file.Close() - return nil, err - } - - if err = file.Close(); err != nil { - return nil, err - } - - return l, err -} diff --git a/vendor/github.com/kavu/go_reuseport/tcp_test.go b/vendor/github.com/kavu/go_reuseport/tcp_test.go deleted file mode 100644 index 1620f9d3..00000000 --- a/vendor/github.com/kavu/go_reuseport/tcp_test.go +++ /dev/null @@ -1,218 +0,0 @@ -// +build linux darwin dragonfly freebsd netbsd openbsd - -// Copyright (C) 2017 Max Riveiro -// -// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: -// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -package reuseport - -import ( - "fmt" - "html" - "io/ioutil" - "net/http" - "net/http/httptest" - "os" - "testing" -) - -const ( - httpServerOneResponse = "1" - httpServerTwoResponse = "2" -) - -var ( - httpServerOne = NewHTTPServer(httpServerOneResponse) - httpServerTwo = NewHTTPServer(httpServerTwoResponse) -) - -func NewHTTPServer(resp string) *httptest.Server { - return httptest.NewUnstartedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - fmt.Fprint(w, resp) - })) -} -func TestNewReusablePortListener(t *testing.T) { - listenerOne, err := NewReusablePortListener("tcp4", "localhost:10081") - if err != nil { - t.Error(err) - } - defer listenerOne.Close() - - listenerTwo, err := NewReusablePortListener("tcp", "127.0.0.1:10081") - if err != nil { - t.Error(err) - } - defer listenerTwo.Close() - - listenerThree, err := NewReusablePortListener("tcp6", "[::1]:10081") - if err != nil { - t.Error(err) - } - defer listenerThree.Close() - - listenerFour, err := NewReusablePortListener("tcp6", ":10081") - if err != nil { - t.Error(err) - } - defer listenerFour.Close() - - listenerFive, err := NewReusablePortListener("tcp4", ":10081") - if err != nil { - t.Error(err) - } - defer listenerFive.Close() - - listenerSix, err := NewReusablePortListener("tcp", ":10081") - if err != nil { - t.Error(err) - } - defer listenerSix.Close() -} - -func TestListen(t *testing.T) { - listenerOne, err := Listen("tcp4", "localhost:10081") - if err != nil { - t.Error(err) - } - defer listenerOne.Close() - - listenerTwo, err := Listen("tcp", "127.0.0.1:10081") - if err != nil { - t.Error(err) - } - defer listenerTwo.Close() - - listenerThree, err := Listen("tcp6", "[::1]:10081") - if err != nil { - t.Error(err) - } - defer listenerThree.Close() - - listenerFour, err := Listen("tcp6", ":10081") - if err != nil { - t.Error(err) - } - defer listenerFour.Close() - - listenerFive, err := Listen("tcp4", ":10081") - if err != nil { - t.Error(err) - } - defer listenerFive.Close() - - listenerSix, err := Listen("tcp", ":10081") - if err != nil { - t.Error(err) - } - defer listenerSix.Close() -} - -func TestNewReusablePortServers(t *testing.T) { - listenerOne, err := NewReusablePortListener("tcp4", "localhost:10081") - if err != nil { - t.Error(err) - } - defer listenerOne.Close() - - listenerTwo, err := NewReusablePortListener("tcp6", ":10081") - if err != nil { - t.Error(err) - } - defer listenerTwo.Close() - - httpServerOne.Listener = listenerOne - httpServerTwo.Listener = listenerTwo - - httpServerOne.Start() - httpServerTwo.Start() - - // Server One — First Response - resp1, err := http.Get(httpServerOne.URL) - if err != nil { - t.Error(err) - } - body1, err := ioutil.ReadAll(resp1.Body) - resp1.Body.Close() - if err != nil { - t.Error(err) - } - if string(body1) != httpServerOneResponse && string(body1) != httpServerTwoResponse { - t.Errorf("Expected %#v or %#v, got %#v.", httpServerOneResponse, httpServerTwoResponse, string(body1)) - } - - // Server Two — First Response - resp2, err := http.Get(httpServerTwo.URL) - if err != nil { - t.Error(err) - } - body2, err := ioutil.ReadAll(resp2.Body) - resp1.Body.Close() - if err != nil { - t.Error(err) - } - if string(body2) != httpServerOneResponse && string(body2) != httpServerTwoResponse { - t.Errorf("Expected %#v or %#v, got %#v.", httpServerOneResponse, httpServerTwoResponse, string(body2)) - } - - httpServerTwo.Close() - - // Server One — Second Response - resp3, err := http.Get(httpServerOne.URL) - if err != nil { - t.Error(err) - } - body3, err := ioutil.ReadAll(resp3.Body) - resp1.Body.Close() - if err != nil { - t.Error(err) - } - if string(body3) != httpServerOneResponse { - t.Errorf("Expected %#v, got %#v.", httpServerOneResponse, string(body3)) - } - - // Server One — Third Response - resp5, err := http.Get(httpServerOne.URL) - if err != nil { - t.Error(err) - } - body5, err := ioutil.ReadAll(resp5.Body) - resp1.Body.Close() - if err != nil { - t.Error(err) - } - if string(body5) != httpServerOneResponse { - t.Errorf("Expected %#v, got %#v.", httpServerOneResponse, string(body5)) - } - - httpServerOne.Close() -} - -func BenchmarkNewReusablePortListener(b *testing.B) { - for i := 0; i < b.N; i++ { - listener, err := NewReusablePortListener("tcp", ":10081") - - if err != nil { - b.Error(err) - } else { - listener.Close() - } - } -} - -func ExampleNewReusablePortListener() { - listener, err := NewReusablePortListener("tcp", ":8881") - if err != nil { - panic(err) - } - defer listener.Close() - - server := &http.Server{} - http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { - fmt.Println(os.Getgid()) - fmt.Fprintf(w, "Hello, %q\n", html.EscapeString(r.URL.Path)) - }) - - panic(server.Serve(listener)) -} diff --git a/vendor/github.com/kavu/go_reuseport/test.bash b/vendor/github.com/kavu/go_reuseport/test.bash deleted file mode 100755 index a57c012a..00000000 --- a/vendor/github.com/kavu/go_reuseport/test.bash +++ /dev/null @@ -1,22 +0,0 @@ -#!/bin/bash - -set -e - -# Thanks to IPFS team -if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then - if [[ "$TRAVIS_SUDO" == true ]]; then - # Ensure that IPv6 is enabled. - # While this is unsupported by TravisCI, it still works for localhost. - sudo sysctl -w net.ipv6.conf.lo.disable_ipv6=0 - sudo sysctl -w net.ipv6.conf.default.disable_ipv6=0 - sudo sysctl -w net.ipv6.conf.all.disable_ipv6=0 - fi -else - # OSX has a default file limit of 256, for some tests we need a - # maximum of 8192. - ulimit -Sn 8192 -fi - -go test -v -cover ./... -go test -v -cover -race ./... -coverprofile=coverage.txt -covermode=atomic -go test -v -cover -race -benchmem -benchtime=5s -bench=. \ No newline at end of file diff --git a/vendor/github.com/kavu/go_reuseport/udp.go b/vendor/github.com/kavu/go_reuseport/udp.go deleted file mode 100644 index 2a9201ce..00000000 --- a/vendor/github.com/kavu/go_reuseport/udp.go +++ /dev/null @@ -1,143 +0,0 @@ -// +build linux darwin dragonfly freebsd netbsd openbsd - -// Copyright (C) 2017 Max Riveiro -// -// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: -// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -package reuseport - -import ( - "errors" - "net" - "os" - "syscall" -) - -var errUnsupportedUDPProtocol = errors.New("only udp, udp4, udp6 are supported") - -func getUDPSockaddr(proto, addr string) (sa syscall.Sockaddr, soType int, err error) { - var udp *net.UDPAddr - - udp, err = net.ResolveUDPAddr(proto, addr) - if err != nil && udp.IP != nil { - return nil, -1, err - } - - udpVersion, err := determineUDPProto(proto, udp) - if err != nil { - return nil, -1, err - } - - switch udpVersion { - case "udp": - return &syscall.SockaddrInet4{Port: udp.Port}, syscall.AF_INET, nil - case "udp4": - sa := &syscall.SockaddrInet4{Port: udp.Port} - - if udp.IP != nil { - copy(sa.Addr[:], udp.IP[12:16]) // copy last 4 bytes of slice to array - } - - return sa, syscall.AF_INET, nil - case "udp6": - sa := &syscall.SockaddrInet6{Port: udp.Port} - - if udp.IP != nil { - copy(sa.Addr[:], udp.IP) // copy all bytes of slice to array - } - - if udp.Zone != "" { - iface, err := net.InterfaceByName(udp.Zone) - if err != nil { - return nil, -1, err - } - - sa.ZoneId = uint32(iface.Index) - } - - return sa, syscall.AF_INET6, nil - } - - return nil, -1, errUnsupportedProtocol -} - -func determineUDPProto(proto string, ip *net.UDPAddr) (string, error) { - // If the protocol is set to "udp", we try to determine the actual protocol - // version from the size of the resolved IP address. Otherwise, we simple use - // the protcol given to us by the caller. - - if ip.IP.To4() != nil { - return "udp4", nil - } - - if ip.IP.To16() != nil { - return "udp6", nil - } - - switch proto { - case "udp", "udp4", "udp6": - return proto, nil - } - - return "", errUnsupportedUDPProtocol -} - -// NewReusablePortPacketConn returns net.FilePacketConn that created from -// a file discriptor for a socket with SO_REUSEPORT option. -func NewReusablePortPacketConn(proto, addr string) (l net.PacketConn, err error) { - var ( - soType, fd int - file *os.File - sockaddr syscall.Sockaddr - ) - - if sockaddr, soType, err = getSockaddr(proto, addr); err != nil { - return nil, err - } - - syscall.ForkLock.RLock() - fd, err = syscall.Socket(soType, syscall.SOCK_DGRAM, syscall.IPPROTO_UDP) - if err == nil { - syscall.CloseOnExec(fd) - } - syscall.ForkLock.RUnlock() - if err != nil { - syscall.Close(fd) - return nil, err - } - - defer func() { - if err != nil { - syscall.Close(fd) - } - }() - - if err = syscall.SetsockoptInt(fd, syscall.SOL_SOCKET, syscall.SO_REUSEADDR, 1); err != nil { - return nil, err - } - - if err = syscall.SetsockoptInt(fd, syscall.SOL_SOCKET, reusePort, 1); err != nil { - return nil, err - } - - if err = syscall.SetsockoptInt(fd, syscall.SOL_SOCKET, syscall.SO_BROADCAST, 1); err != nil { - return nil, err - } - - if err = syscall.Bind(fd, sockaddr); err != nil { - return nil, err - } - - file = os.NewFile(uintptr(fd), getSocketFileName(proto, addr)) - if l, err = net.FilePacketConn(file); err != nil { - return nil, err - } - - if err = file.Close(); err != nil { - return nil, err - } - - return l, err -} diff --git a/vendor/github.com/kavu/go_reuseport/udp_test.go b/vendor/github.com/kavu/go_reuseport/udp_test.go deleted file mode 100644 index d6550e36..00000000 --- a/vendor/github.com/kavu/go_reuseport/udp_test.go +++ /dev/null @@ -1,99 +0,0 @@ -// +build linux darwin dragonfly freebsd netbsd openbsd - -// Copyright (C) 2017 Max Riveiro -// -// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: -// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -package reuseport - -import "testing" - -func TestNewReusablePortPacketConn(t *testing.T) { - listenerOne, err := NewReusablePortPacketConn("udp4", "localhost:10082") - if err != nil { - t.Error(err) - } - defer listenerOne.Close() - - listenerTwo, err := NewReusablePortPacketConn("udp", "127.0.0.1:10082") - if err != nil { - t.Error(err) - } - defer listenerTwo.Close() - - listenerThree, err := NewReusablePortPacketConn("udp6", "[::1]:10082") - if err != nil { - t.Error(err) - } - defer listenerThree.Close() - - listenerFour, err := NewReusablePortListener("udp6", ":10081") - if err != nil { - t.Error(err) - } - defer listenerFour.Close() - - listenerFive, err := NewReusablePortListener("udp4", ":10081") - if err != nil { - t.Error(err) - } - defer listenerFive.Close() - - listenerSix, err := NewReusablePortListener("udp", ":10081") - if err != nil { - t.Error(err) - } - defer listenerSix.Close() -} - -func TestListenPacket(t *testing.T) { - listenerOne, err := ListenPacket("udp4", "localhost:10082") - if err != nil { - t.Error(err) - } - defer listenerOne.Close() - - listenerTwo, err := ListenPacket("udp", "127.0.0.1:10082") - if err != nil { - t.Error(err) - } - defer listenerTwo.Close() - - listenerThree, err := ListenPacket("udp6", "[::1]:10082") - if err != nil { - t.Error(err) - } - defer listenerThree.Close() - - listenerFour, err := ListenPacket("udp6", ":10081") - if err != nil { - t.Error(err) - } - defer listenerFour.Close() - - listenerFive, err := ListenPacket("udp4", ":10081") - if err != nil { - t.Error(err) - } - defer listenerFive.Close() - - listenerSix, err := ListenPacket("udp", ":10081") - if err != nil { - t.Error(err) - } - defer listenerSix.Close() -} - -func BenchmarkNewReusableUDPPortListener(b *testing.B) { - for i := 0; i < b.N; i++ { - listener, err := NewReusablePortPacketConn("udp4", "localhost:10082") - - if err != nil { - b.Error(err) - } else { - listener.Close() - } - } -} diff --git a/vendor/github.com/tidwall/evio/.travis.yml b/vendor/github.com/tidwall/evio/.travis.yml deleted file mode 100644 index c74ca9b9..00000000 --- a/vendor/github.com/tidwall/evio/.travis.yml +++ /dev/null @@ -1,2 +0,0 @@ -language: go -script: go test -run none diff --git a/vendor/github.com/tidwall/evio/LICENSE b/vendor/github.com/tidwall/evio/LICENSE deleted file mode 100644 index 92a9728f..00000000 --- a/vendor/github.com/tidwall/evio/LICENSE +++ /dev/null @@ -1,20 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2017 Joshua J Baker - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software is furnished to do so, -subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/vendor/github.com/tidwall/evio/README.md b/vendor/github.com/tidwall/evio/README.md deleted file mode 100644 index bc5f9678..00000000 --- a/vendor/github.com/tidwall/evio/README.md +++ /dev/null @@ -1,168 +0,0 @@ -

-evio -
-Build Status -GoDoc -

- -`evio` is an event loop networking framework that is fast and small. It makes direct [epoll](https://en.wikipedia.org/wiki/Epoll) and [kqueue](https://en.wikipedia.org/wiki/Kqueue) syscalls rather than using the standard Go [net](https://golang.org/pkg/net/) package, and works in a similar manner as [libuv](https://github.com/libuv/libuv) and [libevent](https://github.com/libevent/libevent). - -The goal of this project is to create a server framework for Go that performs on par with [Redis](http://redis.io) and [Haproxy](http://www.haproxy.org) for packet handling. It was built to be the foundation for [Tile38](https://github.com/tidwall/tile38) and a future L7 proxy for Go. - -*Please note: Evio should not be considered as a drop-in replacement for the standard Go net or net/http packages.* - -## Features - -- [Fast](#performance) single-threaded or [multithreaded](#multithreaded) event loop -- Built-in [load balancing](#load-balancing) options -- Simple API -- Low memory usage -- Supports tcp, [udp](#udp), and unix sockets -- Allows [multiple network binding](#multiple-addresses) on the same event loop -- Flexible [ticker](#ticker) event -- Fallback for non-epoll/kqueue operating systems by simulating events with the [net](https://golang.org/pkg/net/) package -- [SO_REUSEPORT](#so_reuseport) socket option - -## Getting Started - -### Installing - -To start using evio, install Go and run `go get`: - -```sh -$ go get -u github.com/tidwall/evio -``` - -This will retrieve the library. - -### Usage - -Starting a server is easy with `evio`. Just set up your events and pass them to the `Serve` function along with the binding address(es). Each connections is represented as an `evio.Conn` object that is passed to various events to differentiate the clients. At any point you can close a client or shutdown the server by return a `Close` or `Shutdown` action from an event. - -Example echo server that binds to port 5000: - -```go -package main - -import "github.com/tidwall/evio" - -func main() { - var events evio.Events - events.Data = func(c evio.Conn, in []byte) (out []byte, action evio.Action) { - out = in - return - } - if err := evio.Serve(events, "tcp://localhost:5000"); err != nil { - panic(err.Error()) - } -} -``` - -Here the only event being used is `Data`, which fires when the server receives input data from a client. -The exact same input data is then passed through the output return value, which is then sent back to the client. - -Connect to the echo server: - -```sh -$ telnet localhost 5000 -``` - -### Events - -The event type has a bunch of handy events: - -- `Serving` fires when the server is ready to accept new connections. -- `Opened` fires when a connection has opened. -- `Closed` fires when a connection has closed. -- `Detach` fires when a connection has been detached using the `Detach` return action. -- `Data` fires when the server receives new data from a connection. -- `Tick` fires immediately after the server starts and will fire again after a specified interval. - -### Multiple addresses - -A server can bind to multiple addresses and share the same event loop. - -```go -evio.Serve(events, "tcp://192.168.0.10:5000", "unix://socket") -``` - -### Ticker - -The `Tick` event fires ticks at a specified interval. -The first tick fires immediately after the `Serving` events. - -```go -events.Tick = func() (delay time.Duration, action Action){ - log.Printf("tick") - delay = time.Second - return -} -``` - -## UDP - -The `Serve` function can bind to UDP addresses. - -- All incoming and outgoing packets are not buffered and sent individually. -- The `Opened` and `Closed` events are not availble for UDP sockets, only the `Data` event. - -## Multithreaded - -The `events.NumLoops` options sets the number of loops to use for the server. -A value greater than 1 will effectively make the server multithreaded for multi-core machines. -Which means you must take care when synchonizing memory between event callbacks. -Setting to 0 or 1 will run the server as single-threaded. -Setting to -1 will automatically assign this value equal to `runtime.NumProcs()`. - -## Load balancing - -The `events.LoadBalance` options sets the load balancing method. -Load balancing is always a best effort to attempt to distribute the incoming connections between multiple loops. -This option is only available when `events.NumLoops` is set. - -- `Random` requests that connections are randomly distributed. -- `RoundRobin` requests that connections are distributed to a loop in a round-robin fashion. -- `LeastConnections` assigns the next accepted connection to the loop with the least number of active connections. - -## SO_REUSEPORT - -Servers can utilize the [SO_REUSEPORT](https://lwn.net/Articles/542629/) option which allows multiple sockets on the same host to bind to the same port. - -Just provide `reuseport=true` to an address: - -```go -evio.Serve(events, "tcp://0.0.0.0:1234?reuseport=true")) -``` - -## More examples - -Please check out the [examples](examples) subdirectory for a simplified [redis](examples/redis-server/main.go) clone, an [echo](examples/echo-server/main.go) server, and a very basic [http](examples/http-server/main.go) server. - -To run an example: - -```sh -$ go run examples/http-server/main.go -$ go run examples/redis-server/main.go -$ go run examples/echo-server/main.go -``` - -## Performance - -### Benchmarks - -These benchmarks were run on an ec2 c4.xlarge instance in single-threaded mode (GOMAXPROC=1) over Ipv4 localhost. -Check out [benchmarks](benchmarks) for more info. - -echo benchmarkhttp benchmarkredis 1 benchmarkredis 8 benchmark - - -## Contact - -Josh Baker [@tidwall](http://twitter.com/tidwall) - -## License - -`evio` source code is available under the MIT [License](/LICENSE). - diff --git a/vendor/github.com/tidwall/evio/benchmarks/.gitignore b/vendor/github.com/tidwall/evio/benchmarks/.gitignore deleted file mode 100644 index ee984695..00000000 --- a/vendor/github.com/tidwall/evio/benchmarks/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -bin/ -socket \ No newline at end of file diff --git a/vendor/github.com/tidwall/evio/benchmarks/README.md b/vendor/github.com/tidwall/evio/benchmarks/README.md deleted file mode 100644 index 6aa7acba..00000000 --- a/vendor/github.com/tidwall/evio/benchmarks/README.md +++ /dev/null @@ -1,27 +0,0 @@ -## evio benchmark tools - -Required tools: - -- [bombardier](https://github.com/codesenberg/bombardier) for HTTP -- [tcpkali](https://github.com/machinezone/tcpkali) for Echo -- [Redis](http://redis.io) for Redis - -Required Go packages: - -``` -go get gonum.org/v1/plot/... -go get -u github.com/valyala/fasthttp -go get -u github.com/tidwall/redcon -``` - -And of course [Go](https://golang.org) is required. - -Run `bench.sh` for all benchmarks. - -## Notes - -- The current results were run on an Ec2 c4.xlarge instance. -- The servers started in single-threaded mode (GOMAXPROC=1). -- Network clients connected over Ipv4 localhost. - -Like all benchmarks ever made in the history of whatever, YMMV. Please tweak and run in your environment and let me know if you see any glaring issues. diff --git a/vendor/github.com/tidwall/evio/benchmarks/analyze.go b/vendor/github.com/tidwall/evio/benchmarks/analyze.go deleted file mode 100644 index 0b9f4083..00000000 --- a/vendor/github.com/tidwall/evio/benchmarks/analyze.go +++ /dev/null @@ -1,308 +0,0 @@ -package main - -import ( - "fmt" - "io/ioutil" - "math" - "strconv" - "strings" - - "gonum.org/v1/plot" - "gonum.org/v1/plot/plotter" - "gonum.org/v1/plot/plotutil" - "gonum.org/v1/plot/vg" -) - -var category string -var kind string -var connections, commands, pipeline, seconds int -var rate float64 -var values []float64 -var names []string - -func main() { - analyze() - autoplot() -} - -func autoplot() { - if category == "" { - return - } - var title = category - path := strings.Replace("out/"+category+".png", " ", "_", -1) - - plotit( - path, - title, - values, - names, - ) - -} - -func analyze() { - lines := readlines("out/http.txt", "out/echo.txt", "out/redis1.txt", "out/redis8.txt", "out/redis16.txt") - var err error - for _, line := range lines { - rlines := strings.Split(line, "\r") - line = strings.TrimSpace(rlines[len(rlines)-1]) - if strings.HasPrefix(line, "--- ") { - if strings.HasSuffix(line, " START ---") { - autoplot() - category = strings.ToLower(strings.Replace(strings.Replace(line, "--- ", "", -1), " START ---", "", -1)) - category = strings.Replace(category, "bench ", "", -1) - values = nil - names = nil - } else { - kind = strings.ToLower(strings.Replace(strings.Replace(line, "--- ", "", -1), " ---", "", -1)) - } - connections, commands, pipeline, seconds = 0, 0, 0, 0 - } else if strings.HasPrefix(line, "*** ") { - details := strings.Split(strings.ToLower(strings.Replace(line, "*** ", "", -1)), ", ") - for _, item := range details { - if strings.HasSuffix(item, " connections") { - connections, err = strconv.Atoi(strings.Split(item, " ")[0]) - must(err) - } else if strings.HasSuffix(item, " commands") { - commands, err = strconv.Atoi(strings.Split(item, " ")[0]) - must(err) - } else if strings.HasSuffix(item, " commands pipeline") { - pipeline, err = strconv.Atoi(strings.Split(item, " ")[0]) - must(err) - - } else if strings.HasSuffix(item, " seconds") { - seconds, err = strconv.Atoi(strings.Split(item, " ")[0]) - must(err) - } - } - } else { - switch { - case category == "echo": - if strings.HasPrefix(line, "Packet rate estimate: ") { - rate, err = strconv.ParseFloat(strings.Split(strings.Split(line, ": ")[1], "↓,")[0], 64) - must(err) - output() - } - case category == "http": - if strings.HasPrefix(line, "Reqs/sec ") { - rate, err = strconv.ParseFloat( - strings.Split(strings.TrimSpace(strings.Split(line, "Reqs/sec ")[1]), " ")[0], 64) - must(err) - output() - } - case strings.HasPrefix(category, "redis"): - if strings.HasPrefix(line, "PING_INLINE: ") { - rate, err = strconv.ParseFloat(strings.Split(strings.Split(line, ": ")[1], " ")[0], 64) - must(err) - output() - } - } - } - } -} - -func output() { - name := kind - names = append(names, name) - values = append(values, rate) - //csv += fmt.Sprintf("%s,%s,%d,%d,%d,%d,%f\n", category, kind, connections, commands, pipeline, seconds, rate) -} - -func readlines(paths ...string) (lines []string) { - for _, path := range paths { - data, err := ioutil.ReadFile(path) - must(err) - lines = append(lines, strings.Split(string(data), "\n")...) - } - return -} - -func must(err error) { - if err != nil { - panic(err) - } -} - -func plotit(path, title string, values []float64, names []string) { - plot.DefaultFont = "Helvetica" - var groups []plotter.Values - for _, value := range values { - groups = append(groups, plotter.Values{value}) - } - p, err := plot.New() - if err != nil { - panic(err) - } - p.Title.Text = title - p.Y.Tick.Marker = commaTicks{} - p.Y.Label.Text = "Req/s" - bw := 25.0 - w := vg.Points(bw) - var bars []plot.Plotter - var barsp []*plotter.BarChart - for i := 0; i < len(values); i++ { - bar, err := plotter.NewBarChart(groups[i], w) - if err != nil { - panic(err) - } - bar.LineStyle.Width = vg.Length(0) - bar.Color = plotutil.Color(i) - bar.Offset = vg.Length( - (float64(w) * float64(i)) - - (float64(w)*float64(len(values)))/2) - bars = append(bars, bar) - barsp = append(barsp, bar) - } - p.Add(bars...) - for i, name := range names { - p.Legend.Add(fmt.Sprintf("%s (%.0f req/s)", name, values[i]), barsp[i]) - } - - p.Legend.Top = true - p.NominalX("") - - if err := p.Save(7*vg.Inch, 3*vg.Inch, path); err != nil { - panic(err) - } -} - -// PreciseTicks is suitable for the Tick.Marker field of an Axis, it returns a -// set of tick marks with labels that have been rounded less agressively than -// what DefaultTicks provides. -type PreciseTicks struct{} - -// Ticks returns Ticks in a specified range -func (PreciseTicks) Ticks(min, max float64) []plot.Tick { - const suggestedTicks = 3 - - if max <= min { - panic("illegal range") - } - - tens := math.Pow10(int(math.Floor(math.Log10(max - min)))) - n := (max - min) / tens - for n < suggestedTicks-1 { - tens /= 10 - n = (max - min) / tens - } - - majorMult := int(n / (suggestedTicks - 1)) - switch majorMult { - case 7: - majorMult = 6 - case 9: - majorMult = 8 - } - majorDelta := float64(majorMult) * tens - val := math.Floor(min/majorDelta) * majorDelta - // Makes a list of non-truncated y-values. - var labels []float64 - for val <= max { - if val >= min { - labels = append(labels, val) - } - val += majorDelta - } - prec := int(math.Ceil(math.Log10(val)) - math.Floor(math.Log10(majorDelta))) - // Makes a list of big ticks. - var ticks []plot.Tick - for _, v := range labels { - vRounded := round(v, prec) - ticks = append(ticks, plot.Tick{Value: vRounded, Label: strconv.FormatFloat(vRounded, 'f', -1, 64)}) - } - minorDelta := majorDelta / 2 - switch majorMult { - case 3, 6: - minorDelta = majorDelta / 3 - case 5: - minorDelta = majorDelta / 5 - } - - val = math.Floor(min/minorDelta) * minorDelta - for val <= max { - found := false - for _, t := range ticks { - if t.Value == val { - found = true - } - } - if val >= min && val <= max && !found { - ticks = append(ticks, plot.Tick{Value: val}) - } - val += minorDelta - } - return ticks -} - -type commaTicks struct{} - -// Ticks computes the default tick marks, but inserts commas -// into the labels for the major tick marks. -func (commaTicks) Ticks(min, max float64) []plot.Tick { - tks := PreciseTicks{}.Ticks(min, max) - for i, t := range tks { - if t.Label == "" { // Skip minor ticks, they are fine. - continue - } - tks[i].Label = addCommas(t.Label) - } - return tks -} - -// AddCommas adds commas after every 3 characters from right to left. -// NOTE: This function is a quick hack, it doesn't work with decimal -// points, and may have a bunch of other problems. -func addCommas(s string) string { - rev := "" - n := 0 - for i := len(s) - 1; i >= 0; i-- { - rev += string(s[i]) - n++ - if n%3 == 0 { - rev += "," - } - } - s = "" - for i := len(rev) - 1; i >= 0; i-- { - s += string(rev[i]) - } - if strings.HasPrefix(s, ",") { - s = s[1:] - } - return s -} - -// round returns the half away from zero rounded value of x with a prec precision. -// -// Special cases are: -// round(±0) = +0 -// round(±Inf) = ±Inf -// round(NaN) = NaN -func round(x float64, prec int) float64 { - if x == 0 { - // Make sure zero is returned - // without the negative bit set. - return 0 - } - // Fast path for positive precision on integers. - if prec >= 0 && x == math.Trunc(x) { - return x - } - pow := math.Pow10(prec) - intermed := x * pow - if math.IsInf(intermed, 0) { - return x - } - if x < 0 { - x = math.Ceil(intermed - 0.5) - } else { - x = math.Floor(intermed + 0.5) - } - - if x == 0 { - return 0 - } - - return x / pow -} diff --git a/vendor/github.com/tidwall/evio/benchmarks/bench-echo.sh b/vendor/github.com/tidwall/evio/benchmarks/bench-echo.sh deleted file mode 100755 index fbb3f8eb..00000000 --- a/vendor/github.com/tidwall/evio/benchmarks/bench-echo.sh +++ /dev/null @@ -1,36 +0,0 @@ -#!/bin/bash - -set -e - -echo "" -echo "--- BENCH ECHO START ---" -echo "" - -cd $(dirname "${BASH_SOURCE[0]}") -function cleanup { - echo "--- BENCH ECHO DONE ---" - kill -9 $(jobs -rp) - wait $(jobs -rp) 2>/dev/null -} -trap cleanup EXIT - -mkdir -p bin -$(pkill -9 net-echo-server || printf "") -$(pkill -9 evio-echo-server || printf "") - -function gobench { - echo "--- $1 ---" - if [ "$3" != "" ]; then - go build -o $2 $3 - fi - GOMAXPROCS=1 $2 --port $4 & - sleep 1 - echo "*** 50 connections, 10 seconds, 6 byte packets" - nl=$'\r\n' - tcpkali --workers 1 -c 50 -T 10s -m "PING{$nl}" 127.0.0.1:$4 - echo "--- DONE ---" - echo "" -} - -gobench "GO STDLIB" bin/net-echo-server net-echo-server/main.go 5001 -gobench "EVIO" bin/evio-echo-server ../examples/echo-server/main.go 5002 diff --git a/vendor/github.com/tidwall/evio/benchmarks/bench-http.sh b/vendor/github.com/tidwall/evio/benchmarks/bench-http.sh deleted file mode 100755 index 622a9c91..00000000 --- a/vendor/github.com/tidwall/evio/benchmarks/bench-http.sh +++ /dev/null @@ -1,37 +0,0 @@ -#!/bin/bash - -set -e - -echo "" -echo "--- BENCH HTTP START ---" -echo "" - -cd $(dirname "${BASH_SOURCE[0]}") -function cleanup { - echo "--- BENCH HTTP DONE ---" - kill -9 $(jobs -rp) - wait $(jobs -rp) 2>/dev/null -} -trap cleanup EXIT - -mkdir -p bin -$(pkill -9 net-http-server || printf "") -$(pkill -9 fasthttp-server || printf "") -$(pkill -9 evio-http-server || printf "") - -function gobench { - echo "--- $1 ---" - if [ "$3" != "" ]; then - go build -o $2 $3 - fi - GOMAXPROCS=1 $2 --port $4 & - sleep 1 - echo "*** 50 connections, 10 seconds" - bombardier -c 50 http://127.0.0.1:$4 - echo "--- DONE ---" - echo "" -} - -gobench "GO STDLIB" bin/net-http-server net-http-server/main.go 8081 -gobench "FASTHTTP" bin/fasthttp-server fasthttp-server/main.go 8083 -gobench "EVIO" bin/evio-http-server ../examples/http-server/main.go 8084 diff --git a/vendor/github.com/tidwall/evio/benchmarks/bench-redis.sh b/vendor/github.com/tidwall/evio/benchmarks/bench-redis.sh deleted file mode 100755 index 5d783c72..00000000 --- a/vendor/github.com/tidwall/evio/benchmarks/bench-redis.sh +++ /dev/null @@ -1,43 +0,0 @@ -#!/bin/bash - -set -e - -pl=$1 -if [ "$pl" == "" ]; then - pl="1" -fi - -echo "" -echo "--- BENCH REDIS PIPELINE $pl START ---" -echo "" - -cd $(dirname "${BASH_SOURCE[0]}") -function cleanup { - echo "--- BENCH REDIS PIPELINE $pl DONE ---" - kill -9 $(jobs -rp) - wait $(jobs -rp) 2>/dev/null -} -trap cleanup EXIT - -mkdir -p bin -$(pkill -9 redis-server || printf "") -$(pkill -9 evio-redis-server || printf "") - -function gobench { - echo "--- $1 ---" - if [ "$3" != "" ]; then - go build -o $2 $3 - fi - GOMAXPROCS=1 $2 --port $4 & - sleep 1 - echo "*** 50 connections, 1000000 commands, $pl commands pipeline" - redis-benchmark -p $4 -t ping_inline -q -c 50 -P $pl -n 1000000 - # echo "*** 50 connections, 1000000 commands, 10 commands pipeline" - # redis-benchmark -p $4 -t ping_inline -q -c 50 -P 10 -n 1000000 - # echo "*** 50 connections, 1000000 commands, 20 commands pipeline" - # redis-benchmark -p $4 -t ping_inline -q -c 50 -P 20 -n 1000000 - echo "--- DONE ---" - echo "" -} -gobench "REAL REDIS" redis-server "" 6392 -gobench "EVIO REDIS CLONE" bin/evio-redis-server ../examples/redis-server/main.go 6393 diff --git a/vendor/github.com/tidwall/evio/benchmarks/bench.sh b/vendor/github.com/tidwall/evio/benchmarks/bench.sh deleted file mode 100755 index 4f9488d2..00000000 --- a/vendor/github.com/tidwall/evio/benchmarks/bench.sh +++ /dev/null @@ -1,15 +0,0 @@ -#!/bin/bash - -set -e - -cd $(dirname "${BASH_SOURCE[0]}") - -mkdir -p out/ - -./bench-http.sh 2>&1 | tee out/http.txt -./bench-echo.sh 2>&1 | tee out/echo.txt -./bench-redis.sh 1 2>&1 | tee out/redis1.txt -./bench-redis.sh 8 2>&1 | tee out/redis8.txt -./bench-redis.sh 16 2>&1 | tee out/redis16.txt - -go run analyze.go \ No newline at end of file diff --git a/vendor/github.com/tidwall/evio/benchmarks/fasthttp-server/main.go b/vendor/github.com/tidwall/evio/benchmarks/fasthttp-server/main.go deleted file mode 100644 index 247b8c4f..00000000 --- a/vendor/github.com/tidwall/evio/benchmarks/fasthttp-server/main.go +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright 2017 Joshua J Baker. All rights reserved. -// Use of this source code is governed by an MIT-style -// license that can be found in the LICENSE file. - -package main - -import ( - "flag" - "fmt" - "log" - - "github.com/valyala/fasthttp" -) - -var res string - -func main() { - var port int - flag.IntVar(&port, "port", 8080, "server port") - flag.Parse() - go log.Printf("http server started on port %d", port) - err := fasthttp.ListenAndServe(fmt.Sprintf(":%d", port), - func(c *fasthttp.RequestCtx) { - _, werr := c.WriteString("Hello World!\r\n") - if werr != nil { - log.Fatal(werr) - } - }) - if err != nil { - log.Fatal(err) - } -} diff --git a/vendor/github.com/tidwall/evio/benchmarks/net-echo-server/main.go b/vendor/github.com/tidwall/evio/benchmarks/net-echo-server/main.go deleted file mode 100644 index 7240deb9..00000000 --- a/vendor/github.com/tidwall/evio/benchmarks/net-echo-server/main.go +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright 2017 Joshua J Baker. All rights reserved. -// Use of this source code is governed by an MIT-style -// license that can be found in the LICENSE file. - -package main - -import ( - "flag" - "fmt" - "log" - "net" -) - -func main() { - var port int - flag.IntVar(&port, "port", 5000, "server port") - flag.Parse() - ln, err := net.Listen("tcp4", fmt.Sprintf(":%d", port)) - if err != nil { - log.Fatal(err) - } - defer ln.Close() - log.Printf("echo server started on port %d", port) - var id int - for { - conn, err := ln.Accept() - if err != nil { - log.Fatal(err) - } - id++ - go func(id int, conn net.Conn) { - defer func() { - //log.Printf("closed: %d", id) - conn.Close() - }() - //log.Printf("opened: %d: %s", id, conn.RemoteAddr().String()) - var packet [0xFFF]byte - for { - n, err := conn.Read(packet[:]) - if err != nil { - return - } - conn.Write(packet[:n]) - } - }(id, conn) - } -} diff --git a/vendor/github.com/tidwall/evio/benchmarks/net-http-server/main.go b/vendor/github.com/tidwall/evio/benchmarks/net-http-server/main.go deleted file mode 100644 index 6a544c4b..00000000 --- a/vendor/github.com/tidwall/evio/benchmarks/net-http-server/main.go +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright 2017 Joshua J Baker. All rights reserved. -// Use of this source code is governed by an MIT-style -// license that can be found in the LICENSE file. - -package main - -import ( - "flag" - "fmt" - "log" - "net/http" - "strings" -) - -var res string - -func main() { - var port int - var aaaa bool - flag.IntVar(&port, "port", 8080, "server port") - flag.BoolVar(&aaaa, "aaaa", false, "aaaaa....") - flag.Parse() - if aaaa { - res = strings.Repeat("a", 1024) - } else { - res = "Hello World!\r\n" - } - log.Printf("http server started on port %d", port) - http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { - w.Write([]byte(res)) - }) - err := http.ListenAndServe(fmt.Sprintf(":%d", port), nil) - if err != nil { - log.Fatal(err) - } -} diff --git a/vendor/github.com/tidwall/evio/benchmarks/out/echo.png b/vendor/github.com/tidwall/evio/benchmarks/out/echo.png deleted file mode 100644 index dbd9df5fa155c7460e7fa78f410c53aa0bd5a612..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 13583 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 MQSMTz#I48w2LUMiT>t<8 diff --git a/vendor/github.com/tidwall/evio/benchmarks/out/echo.txt b/vendor/github.com/tidwall/evio/benchmarks/out/echo.txt deleted file mode 100644 index dd3c2aa1..00000000 --- a/vendor/github.com/tidwall/evio/benchmarks/out/echo.txt +++ /dev/null @@ -1,34 +0,0 @@ - ---- BENCH ECHO START --- - ---- GO STDLIB --- -2017/11/04 13:13:38 echo server started on port 5001 -*** 50 connections, 10 seconds, 6 byte packets -Destination: [127.0.0.1]:5001 -Interface lo address [127.0.0.1]:0 -Using interface lo to connect to [127.0.0.1]:5001 -Ramped up to 50 connections. -Total data sent: 9165.8 MiB (9610985472 bytes) -Total data received: 8951.1 MiB (9385891515 bytes) -Bandwidth per channel: 303.867⇅ Mbps (37983.4 kBps) -Aggregate bandwidth: 7506.663↓, 7686.689↑ Mbps -Packet rate estimate: 732150.4↓, 659753.8↑ (6↓, 45↑ TCP MSS/op) -Test duration: 10.0027 s. ---- DONE --- - ---- EVIO --- -2017/11/04 13:13:50 echo server started on port 5002 -*** 50 connections, 10 seconds, 6 byte packets -Destination: [127.0.0.1]:5002 -Interface lo address [127.0.0.1]:0 -Using interface lo to connect to [127.0.0.1]:5002 -Ramped up to 50 connections. -Total data sent: 15441.1 MiB (16191127552 bytes) -Total data received: 15430.5 MiB (16180050837 bytes) -Bandwidth per channel: 517.825⇅ Mbps (64728.2 kBps) -Aggregate bandwidth: 12941.205↓, 12950.064↑ Mbps -Packet rate estimate: 1184847.1↓, 1111512.9↑ (12↓, 45↑ TCP MSS/op) -Test duration: 10.0022 s. ---- DONE --- - ---- BENCH ECHO DONE --- diff --git a/vendor/github.com/tidwall/evio/benchmarks/out/http.png b/vendor/github.com/tidwall/evio/benchmarks/out/http.png deleted file mode 100644 index a5ac0ce3a494b879db77aa942f81a55564938673..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 15932 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 zA|fNd)zr*8x8j~Fy-------------------------------------------------------------------] 9s [==============>------------------------------------------------------------] 8s [======================>----------------------------------------------------] 7s [=============================>---------------------------------------------] 6s [=====================================>-------------------------------------] 5s [============================================>------------------------------] 4s [====================================================>----------------------] 3s [===========================================================>---------------] 2s [===================================================================>-------] 1s [===========================================================================] 0s [==========================================================================] 10s -Done! -Statistics Avg Stdev Max - Reqs/sec 42487.26 9452.41 53042 - Latency 1.17ms 742.47us 12.53ms - HTTP codes: - 1xx - 0, 2xx - 424966, 3xx - 0, 4xx - 0, 5xx - 0 - others - 0 - Throughput: 7.82MB/s ---- DONE --- - ---- FASTHTTP --- -2017/11/06 11:43:27 http server started on port 8083 -*** 50 connections, 10 seconds -Bombarding http://127.0.0.1:8083 for 10s using 50 connections - [------------------------------------------------------------------------------] [=======>-------------------------------------------------------------------] 9s [==============>------------------------------------------------------------] 8s [======================>----------------------------------------------------] 7s [=============================>---------------------------------------------] 6s [=====================================>-------------------------------------] 5s [============================================>------------------------------] 4s [====================================================>----------------------] 3s [===========================================================>---------------] 2s [===================================================================>-------] 1s [===========================================================================] 0s [==========================================================================] 10s -Done! -Statistics Avg Stdev Max - Reqs/sec 104926.32 2744.15 117354 - Latency 474.64us 255.41us 11.06ms - HTTP codes: - 1xx - 0, 2xx - 1049311, 3xx - 0, 4xx - 0, 5xx - 0 - others - 0 - Throughput: 21.11MB/s ---- DONE --- - ---- EVIO --- -2017/11/06 11:43:38 http server started on port 8084 -*** 50 connections, 10 seconds -Bombarding http://127.0.0.1:8084 for 10s using 50 connections - [------------------------------------------------------------------------------] [=======>-------------------------------------------------------------------] 9s [==============>------------------------------------------------------------] 8s [======================>----------------------------------------------------] 7s [=============================>---------------------------------------------] 6s [=====================================>-------------------------------------] 5s [============================================>------------------------------] 4s [====================================================>----------------------] 3s [===========================================================>---------------] 2s [===================================================================>-------] 1s [===========================================================================] 0s [==========================================================================] 10s -Done! -Statistics Avg Stdev Max - Reqs/sec 123821.87 2821.88 130897 - Latency 401.99us 121.11us 12.88ms - HTTP codes: - 1xx - 0, 2xx - 1238166, 3xx - 0, 4xx - 0, 5xx - 0 - others - 0 - Throughput: 19.60MB/s ---- DONE --- - ---- BENCH HTTP DONE --- diff --git a/vendor/github.com/tidwall/evio/benchmarks/out/redis1.txt b/vendor/github.com/tidwall/evio/benchmarks/out/redis1.txt deleted file mode 100644 index 839a0c87..00000000 --- a/vendor/github.com/tidwall/evio/benchmarks/out/redis1.txt +++ /dev/null @@ -1,28 +0,0 @@ - ---- BENCH REDIS PIPELINE 1 START --- - ---- REAL REDIS --- -31889:C 04 Nov 13:14:02.373 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo -31889:C 04 Nov 13:14:02.373 # Redis version=4.0.2, bits=64, commit=00000000, modified=0, pid=31889, just started -31889:C 04 Nov 13:14:02.373 # Configuration loaded -31889:M 04 Nov 13:14:02.374 * Increased maximum number of open files to 10032 (it was originally set to 1024). -31889:M 04 Nov 13:14:02.374 * Running mode=standalone, port=6392. -31889:M 04 Nov 13:14:02.374 # WARNING: The TCP backlog setting of 511 cannot be enforced because /proc/sys/net/core/somaxconn is set to the lower value of 128. -31889:M 04 Nov 13:14:02.374 # Server initialized -31889:M 04 Nov 13:14:02.374 # WARNING overcommit_memory is set to 0! Background save may fail under low memory condition. To fix this issue add 'vm.overcommit_memory = 1' to /etc/sysctl.conf and then reboot or run the command 'sysctl vm.overcommit_memory=1' for this to take effect. -31889:M 04 Nov 13:14:02.374 # WARNING you have Transparent Huge Pages (THP) support enabled in your kernel. This will create latency and memory usage issues with Redis. To fix this issue run the command 'echo never > /sys/kernel/mm/transparent_hugepage/enabled' as root, and add it to your /etc/rc.local in order to retain the setting after a reboot. Redis must be restarted after THP is disabled. -31889:M 04 Nov 13:14:02.374 * Ready to accept connections -*** 50 connections, 1000000 commands, 1 commands pipeline -PING_INLINE: -nan PING_INLINE: 171620.00 PING_INLINE: 175064.00 PING_INLINE: 175986.67 PING_INLINE: 176586.00 PING_INLINE: 176886.41 PING_INLINE: 177081.33 PING_INLINE: 177301.14 PING_INLINE: 177444.50 PING_INLINE: 177331.11 PING_INLINE: 177247.20 PING_INLINE: 177178.91 PING_INLINE: 177169.00 PING_INLINE: 177084.31 PING_INLINE: 177083.72 PING_INLINE: 177058.67 PING_INLINE: 177036.50 PING_INLINE: 177041.17 PING_INLINE: 177017.11 PING_INLINE: 177013.69 PING_INLINE: 177009.80 PING_INLINE: 177003.81 PING_INLINE: 177004.36 PING_INLINE: 176991.14 requests per second - ---- DONE --- - ---- EVIO REDIS CLONE --- -2017/11/04 13:14:09 redis server started on port 6393 -2017/11/04 13:14:09 redis server started at socket -*** 50 connections, 1000000 commands, 1 commands pipeline -PING_INLINE: -nan PING_INLINE: 167180.00 PING_INLINE: 173258.00 PING_INLINE: 175005.33 PING_INLINE: 176102.00 PING_INLINE: 176358.41 PING_INLINE: 176593.33 PING_INLINE: 176877.72 PING_INLINE: 177103.00 PING_INLINE: 177186.67 PING_INLINE: 177269.59 PING_INLINE: 177322.19 PING_INLINE: 177363.67 PING_INLINE: 177420.00 PING_INLINE: 177448.86 PING_INLINE: 177411.73 PING_INLINE: 177371.75 PING_INLINE: 177334.59 PING_INLINE: 177310.44 PING_INLINE: 177264.62 PING_INLINE: 177205.00 PING_INLINE: 177171.62 PING_INLINE: 177173.64 PING_INLINE: 177147.92 requests per second - ---- DONE --- - ---- BENCH REDIS PIPELINE 1 DONE --- diff --git a/vendor/github.com/tidwall/evio/benchmarks/out/redis16.txt b/vendor/github.com/tidwall/evio/benchmarks/out/redis16.txt deleted file mode 100644 index 5cf72f3a..00000000 --- a/vendor/github.com/tidwall/evio/benchmarks/out/redis16.txt +++ /dev/null @@ -1,28 +0,0 @@ - ---- BENCH REDIS PIPELINE 16 START --- - ---- REAL REDIS --- -32002:C 04 Nov 13:14:20.410 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo -32002:C 04 Nov 13:14:20.410 # Redis version=4.0.2, bits=64, commit=00000000, modified=0, pid=32002, just started -32002:C 04 Nov 13:14:20.410 # Configuration loaded -32002:M 04 Nov 13:14:20.411 * Increased maximum number of open files to 10032 (it was originally set to 1024). -32002:M 04 Nov 13:14:20.411 * Running mode=standalone, port=6392. -32002:M 04 Nov 13:14:20.412 # WARNING: The TCP backlog setting of 511 cannot be enforced because /proc/sys/net/core/somaxconn is set to the lower value of 128. -32002:M 04 Nov 13:14:20.412 # Server initialized -32002:M 04 Nov 13:14:20.412 # WARNING overcommit_memory is set to 0! Background save may fail under low memory condition. To fix this issue add 'vm.overcommit_memory = 1' to /etc/sysctl.conf and then reboot or run the command 'sysctl vm.overcommit_memory=1' for this to take effect. -32002:M 04 Nov 13:14:20.412 # WARNING you have Transparent Huge Pages (THP) support enabled in your kernel. This will create latency and memory usage issues with Redis. To fix this issue run the command 'echo never > /sys/kernel/mm/transparent_hugepage/enabled' as root, and add it to your /etc/rc.local in order to retain the setting after a reboot. Redis must be restarted after THP is disabled. -32002:M 04 Nov 13:14:20.412 * Ready to accept connections -*** 50 connections, 1000000 commands, 16 commands pipeline -PING_INLINE: 0.00 PING_INLINE: 874135.50 PING_INLINE: 877221.56 PING_INLINE: 877315.62 PING_INLINE: 877810.12 PING_INLINE: 879507.50 requests per second - ---- DONE --- - ---- EVIO REDIS CLONE --- -2017/11/04 13:14:22 redis server started on port 6393 -2017/11/04 13:14:22 redis server started at socket -*** 50 connections, 1000000 commands, 16 commands pipeline -PING_INLINE: -nan PING_INLINE: 2127552.00 PING_INLINE: 2123142.25 requests per second - ---- DONE --- - ---- BENCH REDIS PIPELINE 16 DONE --- diff --git a/vendor/github.com/tidwall/evio/benchmarks/out/redis8.txt b/vendor/github.com/tidwall/evio/benchmarks/out/redis8.txt deleted file mode 100644 index 0a28af33..00000000 --- a/vendor/github.com/tidwall/evio/benchmarks/out/redis8.txt +++ /dev/null @@ -1,28 +0,0 @@ - ---- BENCH REDIS PIPELINE 8 START --- - ---- REAL REDIS --- -31946:C 04 Nov 13:14:16.084 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo -31946:C 04 Nov 13:14:16.084 # Redis version=4.0.2, bits=64, commit=00000000, modified=0, pid=31946, just started -31946:C 04 Nov 13:14:16.084 # Configuration loaded -31946:M 04 Nov 13:14:16.084 * Increased maximum number of open files to 10032 (it was originally set to 1024). -31946:M 04 Nov 13:14:16.085 * Running mode=standalone, port=6392. -31946:M 04 Nov 13:14:16.085 # WARNING: The TCP backlog setting of 511 cannot be enforced because /proc/sys/net/core/somaxconn is set to the lower value of 128. -31946:M 04 Nov 13:14:16.085 # Server initialized -31946:M 04 Nov 13:14:16.085 # WARNING overcommit_memory is set to 0! Background save may fail under low memory condition. To fix this issue add 'vm.overcommit_memory = 1' to /etc/sysctl.conf and then reboot or run the command 'sysctl vm.overcommit_memory=1' for this to take effect. -31946:M 04 Nov 13:14:16.085 # WARNING you have Transparent Huge Pages (THP) support enabled in your kernel. This will create latency and memory usage issues with Redis. To fix this issue run the command 'echo never > /sys/kernel/mm/transparent_hugepage/enabled' as root, and add it to your /etc/rc.local in order to retain the setting after a reboot. Redis must be restarted after THP is disabled. -31946:M 04 Nov 13:14:16.085 * Ready to accept connections -*** 50 connections, 1000000 commands, 8 commands pipeline -PING_INLINE: -nan PING_INLINE: 823072.00 PING_INLINE: 859168.00 PING_INLINE: 870933.31 PING_INLINE: 876680.00 PING_INLINE: 878734.62 requests per second - ---- DONE --- - ---- EVIO REDIS CLONE --- -2017/11/04 13:14:18 redis server started on port 6393 -2017/11/04 13:14:18 redis server started at socket -*** 50 connections, 1000000 commands, 8 commands pipeline -PING_INLINE: -nan PING_INLINE: 1284896.00 PING_INLINE: 1284144.00 PING_INLINE: 1285141.38 PING_INLINE: 1285347.00 requests per second - ---- DONE --- - ---- BENCH REDIS PIPELINE 8 DONE --- diff --git a/vendor/github.com/tidwall/evio/benchmarks/out/redis_pipeline_1.png b/vendor/github.com/tidwall/evio/benchmarks/out/redis_pipeline_1.png deleted file mode 100644 index 29aa07c70dfe6d3b058bea38a8fc542f6a9ac115..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 14936 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 diff --git a/vendor/github.com/tidwall/evio/benchmarks/out/redis_pipeline_8.png b/vendor/github.com/tidwall/evio/benchmarks/out/redis_pipeline_8.png deleted file mode 100644 index 992d42c89a2879e48040b9a3aa8ed436d42cb12c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 16235 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 NC3%(eiRX+S{~zE&&YA!K diff --git a/vendor/github.com/tidwall/evio/evio.go b/vendor/github.com/tidwall/evio/evio.go deleted file mode 100644 index 8e31287d..00000000 --- a/vendor/github.com/tidwall/evio/evio.go +++ /dev/null @@ -1,268 +0,0 @@ -// Copyright 2018 Joshua J Baker. All rights reserved. -// Use of this source code is governed by an MIT-style -// license that can be found in the LICENSE file. - -package evio - -import ( - "io" - "net" - "os" - "strings" - "time" -) - -// Action is an action that occurs after the completion of an event. -type Action int - -const ( - // None indicates that no action should occur following an event. - None Action = iota - // Detach detaches a connection. Not available for UDP connections. - Detach - // Close closes the connection. - Close - // Shutdown shutdowns the server. - Shutdown -) - -// Options are set when the client opens. -type Options struct { - // TCPKeepAlive (SO_KEEPALIVE) socket option. - TCPKeepAlive time.Duration - // ReuseInputBuffer will forces the connection to share and reuse the - // same input packet buffer with all other connections that also use - // this option. - // Default value is false, which means that all input data which is - // passed to the Data event will be a uniquely copied []byte slice. - ReuseInputBuffer bool -} - -// Server represents a server context which provides information about the -// running server and has control functions for managing state. -type Server struct { - // The addrs parameter is an array of listening addresses that align - // with the addr strings passed to the Serve function. - Addrs []net.Addr - // NumLoops is the number of loops that the server is using. - NumLoops int -} - -// Conn is an evio connection. -type Conn interface { - // Context returns a user-defined context. - Context() interface{} - // SetContext sets a user-defined context. - SetContext(interface{}) - // AddrIndex is the index of server address that was passed to the Serve call. - AddrIndex() int - // LocalAddr is the connection's local socket address. - LocalAddr() net.Addr - // RemoteAddr is the connection's remote peer address. - RemoteAddr() net.Addr - // Wake triggers a Data event for this connection. - Wake() -} - -// LoadBalance sets the load balancing method. -type LoadBalance int - -const ( - // Random requests that connections are randomly distributed. - Random LoadBalance = iota - // RoundRobin requests that connections are distributed to a loop in a - // round-robin fashion. - RoundRobin - // LeastConnections assigns the next accepted connection to the loop with - // the least number of active connections. - LeastConnections -) - -// Events represents the server events for the Serve call. -// Each event has an Action return value that is used manage the state -// of the connection and server. -type Events struct { - // NumLoops sets the number of loops to use for the server. Setting this - // to a value greater than 1 will effectively make the server - // multithreaded for multi-core machines. Which means you must take care - // with synchonizing memory between all event callbacks. Setting to 0 or 1 - // will run the server single-threaded. Setting to -1 will automatically - // assign this value equal to runtime.NumProcs(). - NumLoops int - // LoadBalance sets the load balancing method. Load balancing is always a - // best effort to attempt to distribute the incoming connections between - // multiple loops. This option is only works when NumLoops is set. - LoadBalance LoadBalance - // Serving fires when the server can accept connections. The server - // parameter has information and various utilities. - Serving func(server Server) (action Action) - // Opened fires when a new connection has opened. - // The info parameter has information about the connection such as - // it's local and remote address. - // Use the out return value to write data to the connection. - // The opts return value is used to set connection options. - Opened func(c Conn) (out []byte, opts Options, action Action) - // Closed fires when a connection has closed. - // The err parameter is the last known connection error. - Closed func(c Conn, err error) (action Action) - // Detached fires when a connection has been previously detached. - // Once detached it's up to the receiver of this event to manage the - // state of the connection. The Closed event will not be called for - // this connection. - // The conn parameter is a ReadWriteCloser that represents the - // underlying socket connection. It can be freely used in goroutines - // and should be closed when it's no longer needed. - Detached func(c Conn, rwc io.ReadWriteCloser) (action Action) - // PreWrite fires just before any data is written to any client socket. - PreWrite func() - // Data fires when a connection sends the server data. - // The in parameter is the incoming data. - // Use the out return value to write data to the connection. - Data func(c Conn, in []byte) (out []byte, action Action) - // Tick fires immediately after the server starts and will fire again - // following the duration specified by the delay return value. - Tick func() (delay time.Duration, action Action) -} - -// Serve starts handling events for the specified addresses. -// -// Addresses should use a scheme prefix and be formatted -// like `tcp://192.168.0.10:9851` or `unix://socket`. -// Valid network schemes: -// tcp - bind to both IPv4 and IPv6 -// tcp4 - IPv4 -// tcp6 - IPv6 -// udp - bind to both IPv4 and IPv6 -// udp4 - IPv4 -// udp6 - IPv6 -// unix - Unix Domain Socket -// -// The "tcp" network scheme is assumed when one is not specified. -func Serve(events Events, addr ...string) error { - var lns []*listener - defer func() { - for _, ln := range lns { - ln.close() - } - }() - var stdlib bool - for _, addr := range addr { - var ln listener - var stdlibt bool - ln.network, ln.addr, ln.opts, stdlibt = parseAddr(addr) - if stdlibt { - stdlib = true - } - if ln.network == "unix" { - os.RemoveAll(ln.addr) - } - var err error - if ln.network == "udp" { - if ln.opts.reusePort { - ln.pconn, err = reuseportListenPacket(ln.network, ln.addr) - } else { - ln.pconn, err = net.ListenPacket(ln.network, ln.addr) - } - } else { - if ln.opts.reusePort { - ln.ln, err = reuseportListen(ln.network, ln.addr) - } else { - ln.ln, err = net.Listen(ln.network, ln.addr) - } - } - if err != nil { - return err - } - if ln.pconn != nil { - ln.lnaddr = ln.pconn.LocalAddr() - } else { - ln.lnaddr = ln.ln.Addr() - } - if !stdlib { - if err := ln.system(); err != nil { - return err - } - } - lns = append(lns, &ln) - } - if stdlib { - return stdserve(events, lns) - } - return serve(events, lns) -} - -// InputStream is a helper type for managing input streams from inside -// the Data event. -type InputStream struct{ b []byte } - -// Begin accepts a new packet and returns a working sequence of -// unprocessed bytes. -func (is *InputStream) Begin(packet []byte) (data []byte) { - data = packet - if len(is.b) > 0 { - is.b = append(is.b, data...) - data = is.b - } - return data -} - -// End shifts the stream to match the unprocessed data. -func (is *InputStream) End(data []byte) { - if len(data) > 0 { - if len(data) != len(is.b) { - is.b = append(is.b[:0], data...) - } - } else if len(is.b) > 0 { - is.b = is.b[:0] - } -} - -type listener struct { - ln net.Listener - lnaddr net.Addr - pconn net.PacketConn - opts addrOpts - f *os.File - fd int - network string - addr string -} - -type addrOpts struct { - reusePort bool -} - -func parseAddr(addr string) (network, address string, opts addrOpts, stdlib bool) { - network = "tcp" - address = addr - opts.reusePort = false - if strings.Contains(address, "://") { - network = strings.Split(address, "://")[0] - address = strings.Split(address, "://")[1] - } - if strings.HasSuffix(network, "-net") { - stdlib = true - network = network[:len(network)-4] - } - q := strings.Index(address, "?") - if q != -1 { - for _, part := range strings.Split(address[q+1:], "&") { - kv := strings.Split(part, "=") - if len(kv) == 2 { - switch kv[0] { - case "reuseport": - if len(kv[1]) != 0 { - switch kv[1][0] { - default: - opts.reusePort = kv[1][0] >= '1' && kv[1][0] <= '9' - case 'T', 't', 'Y', 'y': - opts.reusePort = true - } - } - } - } - } - address = address[:q] - } - return -} diff --git a/vendor/github.com/tidwall/evio/evio_other.go b/vendor/github.com/tidwall/evio/evio_other.go deleted file mode 100644 index 31b92313..00000000 --- a/vendor/github.com/tidwall/evio/evio_other.go +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright 2018 Joshua J Baker. All rights reserved. -// Use of this source code is governed by an MIT-style -// license that can be found in the LICENSE file. - -// +build !darwin,!netbsd,!freebsd,!openbsd,!dragonfly,!linux - -package evio - -import ( - "errors" - "net" - "os" -) - -func (ln *listener) close() { - if ln.ln != nil { - ln.ln.Close() - } - if ln.pconn != nil { - ln.pconn.Close() - } - if ln.network == "unix" { - os.RemoveAll(ln.addr) - } -} - -func (ln *listener) system() error { - return nil -} - -func serve(events Events, listeners []*listener) error { - return stdserve(events, listeners) -} - -func reuseportListenPacket(proto, addr string) (l net.PacketConn, err error) { - return nil, errors.New("reuseport is not available") -} - -func reuseportListen(proto, addr string) (l net.Listener, err error) { - return nil, errors.New("reuseport is not available") -} diff --git a/vendor/github.com/tidwall/evio/evio_std.go b/vendor/github.com/tidwall/evio/evio_std.go deleted file mode 100644 index 4eb3e27d..00000000 --- a/vendor/github.com/tidwall/evio/evio_std.go +++ /dev/null @@ -1,459 +0,0 @@ -// Copyright 2018 Joshua J Baker. All rights reserved. -// Use of this source code is governed by an MIT-style -// license that can be found in the LICENSE file. - -package evio - -import ( - "errors" - "io" - "net" - "runtime" - "sync" - "sync/atomic" - "time" -) - -var errClosing = errors.New("closing") -var errCloseConns = errors.New("close conns") - -type stdserver struct { - events Events // user events - loops []*stdloop // all the loops - lns []*listener // all the listeners - loopwg sync.WaitGroup // loop close waitgroup - lnwg sync.WaitGroup // listener close waitgroup - cond *sync.Cond // shutdown signaler - serr error // signal error - accepted uintptr // accept counter -} - -type stdudpconn struct { - addrIndex int - localAddr net.Addr - remoteAddr net.Addr - in []byte -} - -func (c *stdudpconn) Context() interface{} { return nil } -func (c *stdudpconn) SetContext(ctx interface{}) {} -func (c *stdudpconn) AddrIndex() int { return c.addrIndex } -func (c *stdudpconn) LocalAddr() net.Addr { return c.localAddr } -func (c *stdudpconn) RemoteAddr() net.Addr { return c.remoteAddr } -func (c *stdudpconn) Wake() {} - -type stdloop struct { - idx int // loop index - ch chan interface{} // command channel - conns map[*stdconn]bool // track all the conns bound to this loop -} - -type stdconn struct { - addrIndex int - localAddr net.Addr - remoteAddr net.Addr - conn net.Conn // original connection - ctx interface{} // user-defined context - loop *stdloop // owner loop - lnidx int // index of listener - donein []byte // extra data for done connection - done int32 // 0: attached, 1: closed, 2: detached -} - -type wakeReq struct { - c *stdconn -} - -func (c *stdconn) Context() interface{} { return c.ctx } -func (c *stdconn) SetContext(ctx interface{}) { c.ctx = ctx } -func (c *stdconn) AddrIndex() int { return c.addrIndex } -func (c *stdconn) LocalAddr() net.Addr { return c.localAddr } -func (c *stdconn) RemoteAddr() net.Addr { return c.remoteAddr } -func (c *stdconn) Wake() { c.loop.ch <- wakeReq{c} } - -type stdin struct { - c *stdconn - in []byte -} - -type stderr struct { - c *stdconn - err error -} - -// waitForShutdown waits for a signal to shutdown -func (s *stdserver) waitForShutdown() error { - s.cond.L.Lock() - s.cond.Wait() - err := s.serr - s.cond.L.Unlock() - return err -} - -// signalShutdown signals a shutdown an begins server closing -func (s *stdserver) signalShutdown(err error) { - s.cond.L.Lock() - s.serr = err - s.cond.Signal() - s.cond.L.Unlock() -} - -func stdserve(events Events, listeners []*listener) error { - numLoops := events.NumLoops - if numLoops <= 0 { - if numLoops == 0 { - numLoops = 1 - } else { - numLoops = runtime.NumCPU() - } - } - - s := &stdserver{} - s.events = events - s.lns = listeners - s.cond = sync.NewCond(&sync.Mutex{}) - - //println("-- server starting") - if events.Serving != nil { - var svr Server - svr.NumLoops = numLoops - svr.Addrs = make([]net.Addr, len(listeners)) - for i, ln := range listeners { - svr.Addrs[i] = ln.lnaddr - } - action := events.Serving(svr) - switch action { - case Shutdown: - return nil - } - } - for i := 0; i < numLoops; i++ { - s.loops = append(s.loops, &stdloop{ - idx: i, - ch: make(chan interface{}), - conns: make(map[*stdconn]bool), - }) - } - var ferr error - defer func() { - // wait on a signal for shutdown - ferr = s.waitForShutdown() - - // notify all loops to close by closing all listeners - for _, l := range s.loops { - l.ch <- errClosing - } - - // wait on all loops to main loop channel events - s.loopwg.Wait() - - // shutdown all listeners - for i := 0; i < len(s.lns); i++ { - s.lns[i].close() - } - - // wait on all listeners to complete - s.lnwg.Wait() - - // close all connections - s.loopwg.Add(len(s.loops)) - for _, l := range s.loops { - l.ch <- errCloseConns - } - s.loopwg.Wait() - - }() - s.loopwg.Add(numLoops) - for i := 0; i < numLoops; i++ { - go stdloopRun(s, s.loops[i]) - } - s.lnwg.Add(len(listeners)) - for i := 0; i < len(listeners); i++ { - go stdlistenerRun(s, listeners[i], i) - } - return ferr -} - -func stdlistenerRun(s *stdserver, ln *listener, lnidx int) { - var ferr error - defer func() { - s.signalShutdown(ferr) - s.lnwg.Done() - }() - var packet [0xFFFF]byte - for { - if ln.pconn != nil { - // udp - n, addr, err := ln.pconn.ReadFrom(packet[:]) - if err != nil { - ferr = err - return - } - l := s.loops[int(atomic.AddUintptr(&s.accepted, 1))%len(s.loops)] - l.ch <- &stdudpconn{ - addrIndex: lnidx, - localAddr: ln.lnaddr, - remoteAddr: addr, - in: append([]byte{}, packet[:n]...), - } - } else { - // tcp - conn, err := ln.ln.Accept() - if err != nil { - ferr = err - return - } - l := s.loops[int(atomic.AddUintptr(&s.accepted, 1))%len(s.loops)] - c := &stdconn{conn: conn, loop: l, lnidx: lnidx} - l.ch <- c - go func(c *stdconn) { - var packet [0xFFFF]byte - for { - n, err := c.conn.Read(packet[:]) - if err != nil { - c.conn.SetReadDeadline(time.Time{}) - l.ch <- &stderr{c, err} - return - } - l.ch <- &stdin{c, append([]byte{}, packet[:n]...)} - } - }(c) - } - } -} - -func stdloopRun(s *stdserver, l *stdloop) { - var err error - tick := make(chan bool) - tock := make(chan time.Duration) - defer func() { - //fmt.Println("-- loop stopped --", l.idx) - if l.idx == 0 && s.events.Tick != nil { - close(tock) - go func() { - for range tick { - } - }() - } - s.signalShutdown(err) - s.loopwg.Done() - stdloopEgress(s, l) - s.loopwg.Done() - }() - if l.idx == 0 && s.events.Tick != nil { - go func() { - for { - tick <- true - delay, ok := <-tock - if !ok { - break - } - time.Sleep(delay) - } - }() - } - //fmt.Println("-- loop started --", l.idx) - for { - select { - case <-tick: - delay, action := s.events.Tick() - switch action { - case Shutdown: - err = errClosing - } - tock <- delay - case v := <-l.ch: - switch v := v.(type) { - case error: - err = v - case *stdconn: - err = stdloopAccept(s, l, v) - case *stdin: - err = stdloopRead(s, l, v.c, v.in) - case *stdudpconn: - err = stdloopReadUDP(s, l, v) - case *stderr: - err = stdloopError(s, l, v.c, v.err) - case wakeReq: - err = stdloopRead(s, l, v.c, nil) - } - } - if err != nil { - return - } - } -} - -func stdloopEgress(s *stdserver, l *stdloop) { - var closed bool -loop: - for v := range l.ch { - switch v := v.(type) { - case error: - if v == errCloseConns { - closed = true - for c := range l.conns { - stdloopClose(s, l, c) - } - } - case *stderr: - stdloopError(s, l, v.c, v.err) - } - if len(l.conns) == 0 && closed { - break loop - } - } -} - -func stdloopError(s *stdserver, l *stdloop, c *stdconn, err error) error { - delete(l.conns, c) - closeEvent := true - switch atomic.LoadInt32(&c.done) { - case 0: // read error - c.conn.Close() - if err == io.EOF { - err = nil - } - case 1: // closed - c.conn.Close() - err = nil - case 2: // detached - err = nil - if s.events.Detached == nil { - c.conn.Close() - } else { - closeEvent = false - switch s.events.Detached(c, &stddetachedConn{c.conn, c.donein}) { - case Shutdown: - return errClosing - } - } - } - if closeEvent { - if s.events.Closed != nil { - switch s.events.Closed(c, err) { - case Shutdown: - return errClosing - } - } - } - return nil -} - -type stddetachedConn struct { - conn net.Conn // original conn - in []byte // extra input data -} - -func (c *stddetachedConn) Read(p []byte) (n int, err error) { - if len(c.in) > 0 { - if len(c.in) <= len(p) { - copy(p, c.in) - n = len(c.in) - c.in = nil - return - } - copy(p, c.in[:len(p)]) - n = len(p) - c.in = c.in[n:] - return - } - return c.conn.Read(p) -} - -func (c *stddetachedConn) Write(p []byte) (n int, err error) { - return c.conn.Write(p) -} - -func (c *stddetachedConn) Close() error { - return c.conn.Close() -} - -func (c *stddetachedConn) Wake() {} - -func stdloopRead(s *stdserver, l *stdloop, c *stdconn, in []byte) error { - if atomic.LoadInt32(&c.done) == 2 { - // should not ignore reads for detached connections - c.donein = append(c.donein, in...) - return nil - } - if s.events.Data != nil { - out, action := s.events.Data(c, in) - if len(out) > 0 { - if s.events.PreWrite != nil { - s.events.PreWrite() - } - c.conn.Write(out) - } - switch action { - case Shutdown: - return errClosing - case Detach: - return stdloopDetach(s, l, c) - case Close: - return stdloopClose(s, l, c) - } - } - return nil -} - -func stdloopReadUDP(s *stdserver, l *stdloop, c *stdudpconn) error { - if s.events.Data != nil { - out, action := s.events.Data(c, c.in) - if len(out) > 0 { - if s.events.PreWrite != nil { - s.events.PreWrite() - } - s.lns[c.addrIndex].pconn.WriteTo(out, c.remoteAddr) - } - switch action { - case Shutdown: - return errClosing - } - } - return nil -} - -func stdloopDetach(s *stdserver, l *stdloop, c *stdconn) error { - atomic.StoreInt32(&c.done, 2) - c.conn.SetReadDeadline(time.Now()) - return nil -} - -func stdloopClose(s *stdserver, l *stdloop, c *stdconn) error { - atomic.StoreInt32(&c.done, 1) - c.conn.SetReadDeadline(time.Now()) - return nil -} - -func stdloopAccept(s *stdserver, l *stdloop, c *stdconn) error { - l.conns[c] = true - c.addrIndex = c.lnidx - c.localAddr = s.lns[c.lnidx].lnaddr - c.remoteAddr = c.conn.RemoteAddr() - - if s.events.Opened != nil { - out, opts, action := s.events.Opened(c) - if len(out) > 0 { - if s.events.PreWrite != nil { - s.events.PreWrite() - } - c.conn.Write(out) - } - if opts.TCPKeepAlive > 0 { - if c, ok := c.conn.(*net.TCPConn); ok { - c.SetKeepAlive(true) - c.SetKeepAlivePeriod(opts.TCPKeepAlive) - } - } - switch action { - case Shutdown: - return errClosing - case Detach: - return stdloopDetach(s, l, c) - case Close: - return stdloopClose(s, l, c) - } - } - return nil -} diff --git a/vendor/github.com/tidwall/evio/evio_test.go b/vendor/github.com/tidwall/evio/evio_test.go deleted file mode 100644 index ec37b968..00000000 --- a/vendor/github.com/tidwall/evio/evio_test.go +++ /dev/null @@ -1,478 +0,0 @@ -// Copyright 2017 Joshua J Baker. All rights reserved. -// Use of this source code is governed by an MIT-style -// license that can be found in the LICENSE file. - -package evio - -import ( - "bufio" - "fmt" - "io" - "math/rand" - "net" - "os" - "strings" - "sync" - "sync/atomic" - "testing" - "time" -) - -func TestServe(t *testing.T) { - // start a server - // connect 10 clients - // each client will pipe random data for 1-3 seconds. - // the writes to the server will be random sizes. 0KB - 1MB. - // the server will echo back the data. - // waits for graceful connection closing. - t.Run("stdlib", func(t *testing.T) { - t.Run("tcp", func(t *testing.T) { - t.Run("1-loop", func(t *testing.T) { - testServe("tcp-net", ":9997", false, 10, 1, Random) - }) - t.Run("5-loop", func(t *testing.T) { - testServe("tcp-net", ":9998", false, 10, 5, LeastConnections) - }) - t.Run("N-loop", func(t *testing.T) { - testServe("tcp-net", ":9999", false, 10, -1, RoundRobin) - }) - }) - t.Run("unix", func(t *testing.T) { - t.Run("1-loop", func(t *testing.T) { - testServe("tcp-net", ":9989", true, 10, 1, Random) - }) - t.Run("5-loop", func(t *testing.T) { - testServe("tcp-net", ":9988", true, 10, 5, LeastConnections) - }) - t.Run("N-loop", func(t *testing.T) { - testServe("tcp-net", ":9987", true, 10, -1, RoundRobin) - }) - }) - }) - t.Run("poll", func(t *testing.T) { - t.Run("tcp", func(t *testing.T) { - t.Run("1-loop", func(t *testing.T) { - testServe("tcp", ":9991", false, 10, 1, Random) - }) - t.Run("5-loop", func(t *testing.T) { - testServe("tcp", ":9992", false, 10, 5, LeastConnections) - }) - t.Run("N-loop", func(t *testing.T) { - testServe("tcp", ":9993", false, 10, -1, RoundRobin) - }) - }) - t.Run("unix", func(t *testing.T) { - t.Run("1-loop", func(t *testing.T) { - testServe("tcp", ":9994", true, 10, 1, Random) - }) - t.Run("5-loop", func(t *testing.T) { - testServe("tcp", ":9995", true, 10, 5, LeastConnections) - }) - t.Run("N-loop", func(t *testing.T) { - testServe("tcp", ":9996", true, 10, -1, RoundRobin) - }) - }) - }) - -} - -func testServe(network, addr string, unix bool, nclients, nloops int, balance LoadBalance) { - var started int32 - var connected int32 - var disconnected int32 - - var events Events - events.LoadBalance = balance - events.NumLoops = nloops - events.Serving = func(srv Server) (action Action) { - return - } - events.Opened = func(c Conn) (out []byte, opts Options, action Action) { - c.SetContext(c) - atomic.AddInt32(&connected, 1) - out = []byte("sweetness\r\n") - opts.TCPKeepAlive = time.Minute * 5 - if c.LocalAddr() == nil { - panic("nil local addr") - } - if c.RemoteAddr() == nil { - panic("nil local addr") - } - return - } - events.Closed = func(c Conn, err error) (action Action) { - if c.Context() != c { - panic("invalid context") - } - atomic.AddInt32(&disconnected, 1) - if atomic.LoadInt32(&connected) == atomic.LoadInt32(&disconnected) && - atomic.LoadInt32(&disconnected) == int32(nclients) { - action = Shutdown - } - return - } - events.Data = func(c Conn, in []byte) (out []byte, action Action) { - out = in - return - } - events.Tick = func() (delay time.Duration, action Action) { - if atomic.LoadInt32(&started) == 0 { - for i := 0; i < nclients; i++ { - go startClient(network, addr, nloops) - } - atomic.StoreInt32(&started, 1) - } - delay = time.Second / 5 - return - } - var err error - if unix { - socket := strings.Replace(addr, ":", "socket", 1) - os.RemoveAll(socket) - defer os.RemoveAll(socket) - err = Serve(events, network+"://"+addr, "unix://"+socket) - } else { - err = Serve(events, network+"://"+addr) - } - if err != nil { - panic(err) - } -} - -func startClient(network, addr string, nloops int) { - onetwork := network - network = strings.Replace(network, "-net", "", -1) - rand.Seed(time.Now().UnixNano()) - c, err := net.Dial(network, addr) - if err != nil { - panic(err) - } - defer c.Close() - rd := bufio.NewReader(c) - msg, err := rd.ReadBytes('\n') - if err != nil { - panic(err) - } - if string(msg) != "sweetness\r\n" { - panic("bad header") - } - duration := time.Duration((rand.Float64()*2+1)*float64(time.Second)) / 8 - start := time.Now() - for time.Since(start) < duration { - sz := rand.Int() % (1024 * 1024) - data := make([]byte, sz) - if _, err := rand.Read(data); err != nil { - panic(err) - } - if _, err := c.Write(data); err != nil { - panic(err) - } - data2 := make([]byte, len(data)) - if _, err := io.ReadFull(rd, data2); err != nil { - panic(err) - } - if string(data) != string(data2) { - fmt.Printf("mismatch %s/%d: %d vs %d bytes\n", onetwork, nloops, len(data), len(data2)) - //panic("mismatch") - } - } -} - -func must(err error) { - if err != nil { - panic(err) - } -} -func TestTick(t *testing.T) { - var wg sync.WaitGroup - wg.Add(1) - go func() { - defer wg.Done() - testTick("tcp", ":9991", false) - }() - wg.Add(1) - go func() { - defer wg.Done() - testTick("tcp", ":9992", true) - }() - wg.Add(1) - go func() { - defer wg.Done() - testTick("unix", "socket1", false) - }() - wg.Add(1) - go func() { - defer wg.Done() - testTick("unix", "socket2", true) - }() - wg.Wait() -} -func testTick(network, addr string, stdlib bool) { - var events Events - var count int - start := time.Now() - events.Tick = func() (delay time.Duration, action Action) { - if count == 25 { - action = Shutdown - return - } - count++ - delay = time.Millisecond * 10 - return - } - if stdlib { - must(Serve(events, network+"-net://"+addr)) - } else { - must(Serve(events, network+"://"+addr)) - } - dur := time.Since(start) - if dur < 250&time.Millisecond || dur > time.Second { - panic("bad ticker timing") - } -} - -func TestShutdown(t *testing.T) { - var wg sync.WaitGroup - wg.Add(1) - go func() { - defer wg.Done() - testShutdown("tcp", ":9991", false) - }() - wg.Add(1) - go func() { - defer wg.Done() - testShutdown("tcp", ":9992", true) - }() - wg.Add(1) - go func() { - defer wg.Done() - testShutdown("unix", "socket1", false) - }() - wg.Add(1) - go func() { - defer wg.Done() - testShutdown("unix", "socket2", true) - }() - wg.Wait() -} -func testShutdown(network, addr string, stdlib bool) { - var events Events - var count int - var clients int64 - var N = 10 - events.Opened = func(c Conn) (out []byte, opts Options, action Action) { - atomic.AddInt64(&clients, 1) - return - } - events.Closed = func(c Conn, err error) (action Action) { - atomic.AddInt64(&clients, -1) - return - } - events.Tick = func() (delay time.Duration, action Action) { - if count == 0 { - // start clients - for i := 0; i < N; i++ { - go func() { - conn, err := net.Dial(network, addr) - must(err) - defer conn.Close() - _, err = conn.Read([]byte{0}) - if err == nil { - panic("expected error") - } - }() - } - } else { - if int(atomic.LoadInt64(&clients)) == N { - action = Shutdown - } - } - count++ - delay = time.Second / 20 - return - } - if stdlib { - must(Serve(events, network+"-net://"+addr)) - } else { - must(Serve(events, network+"://"+addr)) - } - if clients != 0 { - panic("did not call close on all clients") - } -} - -func TestDetach(t *testing.T) { - t.Run("poll", func(t *testing.T) { - t.Run("tcp", func(t *testing.T) { - testDetach("tcp", ":9991", false) - }) - t.Run("unix", func(t *testing.T) { - testDetach("unix", "socket1", false) - }) - }) - t.Run("stdlib", func(t *testing.T) { - t.Run("tcp", func(t *testing.T) { - testDetach("tcp", ":9992", true) - }) - t.Run("unix", func(t *testing.T) { - testDetach("unix", "socket2", true) - }) - }) -} - -func testDetach(network, addr string, stdlib bool) { - // we will write a bunch of data with the text "--detached--" in the - // middle followed by a bunch of data. - rand.Seed(time.Now().UnixNano()) - rdat := make([]byte, 10*1024) - if _, err := rand.Read(rdat); err != nil { - panic("random error: " + err.Error()) - } - expected := []byte(string(rdat) + "--detached--" + string(rdat)) - var cin []byte - var events Events - events.Data = func(c Conn, in []byte) (out []byte, action Action) { - cin = append(cin, in...) - if len(cin) >= len(expected) { - if string(cin) != string(expected) { - panic("mismatch client -> server") - } - return cin, Detach - } - return - } - - var done int64 - events.Detached = func(c Conn, conn io.ReadWriteCloser) (action Action) { - go func() { - p := make([]byte, len(expected)) - defer conn.Close() - _, err := io.ReadFull(conn, p) - must(err) - conn.Write(expected) - }() - return - } - - events.Serving = func(srv Server) (action Action) { - go func() { - p := make([]byte, len(expected)) - _ = expected - conn, err := net.Dial(network, addr) - must(err) - defer conn.Close() - conn.Write(expected) - _, err = io.ReadFull(conn, p) - must(err) - conn.Write(expected) - _, err = io.ReadFull(conn, p) - must(err) - atomic.StoreInt64(&done, 1) - }() - return - } - events.Tick = func() (delay time.Duration, action Action) { - delay = time.Second / 5 - if atomic.LoadInt64(&done) == 1 { - action = Shutdown - } - return - } - if stdlib { - must(Serve(events, network+"-net://"+addr)) - } else { - must(Serve(events, network+"://"+addr)) - } -} - -func TestBadAddresses(t *testing.T) { - var events Events - events.Serving = func(srv Server) (action Action) { - return Shutdown - } - if err := Serve(events, "tulip://howdy"); err == nil { - t.Fatalf("expected error") - } - if err := Serve(events, "howdy"); err == nil { - t.Fatalf("expected error") - } - if err := Serve(events, "tcp://"); err != nil { - t.Fatalf("expected nil, got '%v'", err) - } -} - -func TestInputStream(t *testing.T) { - var s InputStream - in := []byte("HELLO") - data := s.Begin(in) - if string(data) != string(in) { - t.Fatalf("expected '%v', got '%v'", in, data) - } - s.End(in[3:]) - data = s.Begin([]byte("WLY")) - if string(data) != "LOWLY" { - t.Fatalf("expected '%v', got '%v'", "LOWLY", data) - } - s.End(nil) - data = s.Begin([]byte("PLAYER")) - if string(data) != "PLAYER" { - t.Fatalf("expected '%v', got '%v'", "PLAYER", data) - } -} - -func TestReuseInputBuffer(t *testing.T) { - reuses := []bool{true, false} - for _, reuse := range reuses { - var events Events - events.Opened = func(c Conn) (out []byte, opts Options, action Action) { - opts.ReuseInputBuffer = reuse - return - } - var prev []byte - events.Data = func(c Conn, in []byte) (out []byte, action Action) { - if prev == nil { - prev = in - } else { - reused := string(in) == string(prev) - if reused != reuse { - t.Fatalf("expected %v, got %v", reuse, reused) - } - action = Shutdown - } - return - } - events.Serving = func(_ Server) (action Action) { - go func() { - c, err := net.Dial("tcp", ":9991") - must(err) - defer c.Close() - c.Write([]byte("packet1")) - time.Sleep(time.Second / 5) - c.Write([]byte("packet2")) - }() - return - } - must(Serve(events, "tcp://:9991")) - } - -} - -func TestReuseport(t *testing.T) { - var events Events - events.Serving = func(s Server) (action Action) { - return Shutdown - } - var wg sync.WaitGroup - wg.Add(5) - for i := 0; i < 5; i++ { - var t = "1" - if i%2 == 0 { - t = "true" - } - go func(t string) { - defer wg.Done() - must(Serve(events, "tcp://:9991?reuseport="+t)) - }(t) - } - wg.Wait() -} diff --git a/vendor/github.com/tidwall/evio/evio_unix.go b/vendor/github.com/tidwall/evio/evio_unix.go deleted file mode 100644 index 16c696e5..00000000 --- a/vendor/github.com/tidwall/evio/evio_unix.go +++ /dev/null @@ -1,534 +0,0 @@ -// Copyright 2018 Joshua J Baker. All rights reserved. -// Use of this source code is governed by an MIT-style -// license that can be found in the LICENSE file. - -// +build darwin netbsd freebsd openbsd dragonfly linux - -package evio - -import ( - "io" - "net" - "os" - "runtime" - "sync" - "sync/atomic" - "syscall" - "time" - - reuseport "github.com/kavu/go_reuseport" - "github.com/tidwall/evio/internal" -) - -type conn struct { - fd int // file descriptor - lnidx int // listener index in the server lns list - out []byte // write buffer - sa syscall.Sockaddr // remote socket address - reuse bool // should reuse input buffer - opened bool // connection opened event fired - action Action // next user action - ctx interface{} // user-defined context - addrIndex int // index of listening address - localAddr net.Addr // local addre - remoteAddr net.Addr // remote addr - loop *loop // connected loop -} - -func (c *conn) Context() interface{} { return c.ctx } -func (c *conn) SetContext(ctx interface{}) { c.ctx = ctx } -func (c *conn) AddrIndex() int { return c.addrIndex } -func (c *conn) LocalAddr() net.Addr { return c.localAddr } -func (c *conn) RemoteAddr() net.Addr { return c.remoteAddr } -func (c *conn) Wake() { - if c.loop != nil { - c.loop.poll.Trigger(c) - } -} - -type server struct { - events Events // user events - loops []*loop // all the loops - lns []*listener // all the listeners - wg sync.WaitGroup // loop close waitgroup - cond *sync.Cond // shutdown signaler - balance LoadBalance // load balancing method - accepted uintptr // accept counter - tch chan time.Duration // ticker channel - - //ticktm time.Time // next tick time -} - -type loop struct { - idx int // loop index in the server loops list - poll *internal.Poll // epoll or kqueue - packet []byte // read packet buffer - fdconns map[int]*conn // loop connections fd -> conn - count int32 // connection count -} - -// waitForShutdown waits for a signal to shutdown -func (s *server) waitForShutdown() { - s.cond.L.Lock() - s.cond.Wait() - s.cond.L.Unlock() -} - -// signalShutdown signals a shutdown an begins server closing -func (s *server) signalShutdown() { - s.cond.L.Lock() - s.cond.Signal() - s.cond.L.Unlock() -} - -func serve(events Events, listeners []*listener) error { - // figure out the correct number of loops/goroutines to use. - numLoops := events.NumLoops - if numLoops <= 0 { - if numLoops == 0 { - numLoops = 1 - } else { - numLoops = runtime.NumCPU() - } - } - - s := &server{} - s.events = events - s.lns = listeners - s.cond = sync.NewCond(&sync.Mutex{}) - s.balance = events.LoadBalance - s.tch = make(chan time.Duration) - - //println("-- server starting") - if s.events.Serving != nil { - var svr Server - svr.NumLoops = numLoops - svr.Addrs = make([]net.Addr, len(listeners)) - for i, ln := range listeners { - svr.Addrs[i] = ln.lnaddr - } - action := s.events.Serving(svr) - switch action { - case None: - case Shutdown: - return nil - } - } - - defer func() { - // wait on a signal for shutdown - s.waitForShutdown() - - // notify all loops to close by closing all listeners - for _, l := range s.loops { - l.poll.Trigger(errClosing) - } - - // wait on all loops to complete reading events - s.wg.Wait() - - // close loops and all outstanding connections - for _, l := range s.loops { - for _, c := range l.fdconns { - loopCloseConn(s, l, c, nil) - } - l.poll.Close() - } - //println("-- server stopped") - }() - - // create loops locally and bind the listeners. - for i := 0; i < numLoops; i++ { - l := &loop{ - idx: i, - poll: internal.OpenPoll(), - packet: make([]byte, 0xFFFF), - fdconns: make(map[int]*conn), - } - for _, ln := range listeners { - l.poll.AddRead(ln.fd) - } - s.loops = append(s.loops, l) - } - // start loops in background - s.wg.Add(len(s.loops)) - for _, l := range s.loops { - go loopRun(s, l) - } - return nil -} - -func loopCloseConn(s *server, l *loop, c *conn, err error) error { - atomic.AddInt32(&l.count, -1) - delete(l.fdconns, c.fd) - syscall.Close(c.fd) - if s.events.Closed != nil { - switch s.events.Closed(c, err) { - case None: - case Shutdown: - return errClosing - } - } - return nil -} - -func loopDetachConn(s *server, l *loop, c *conn, err error) error { - if s.events.Detached == nil { - return loopCloseConn(s, l, c, err) - } - l.poll.ModDetach(c.fd) - - atomic.AddInt32(&l.count, -1) - delete(l.fdconns, c.fd) - if err := syscall.SetNonblock(c.fd, false); err != nil { - return err - } - switch s.events.Detached(c, &detachedConn{fd: c.fd}) { - case None: - case Shutdown: - return errClosing - } - return nil -} - -func loopNote(s *server, l *loop, note interface{}) error { - var err error - switch v := note.(type) { - case time.Duration: - delay, action := s.events.Tick() - switch action { - case None: - case Shutdown: - err = errClosing - } - s.tch <- delay - case error: // shutdown - err = v - case *conn: - // Wake called for connection - if l.fdconns[v.fd] != v { - return nil // ignore stale wakes - } - return loopWake(s, l, v) - } - return err -} - -func loopRun(s *server, l *loop) { - defer func() { - //fmt.Println("-- loop stopped --", l.idx) - s.signalShutdown() - s.wg.Done() - }() - - if l.idx == 0 && s.events.Tick != nil { - go loopTicker(s, l) - } - - //fmt.Println("-- loop started --", l.idx) - l.poll.Wait(func(fd int, note interface{}) error { - if fd == 0 { - return loopNote(s, l, note) - } - c := l.fdconns[fd] - switch { - case c == nil: - return loopAccept(s, l, fd) - case !c.opened: - return loopOpened(s, l, c) - case len(c.out) > 0: - return loopWrite(s, l, c) - case c.action != None: - return loopAction(s, l, c) - default: - return loopRead(s, l, c) - } - }) -} - -func loopTicker(s *server, l *loop) { - for { - if err := l.poll.Trigger(time.Duration(0)); err != nil { - break - } - time.Sleep(<-s.tch) - } -} - -func loopAccept(s *server, l *loop, fd int) error { - for i, ln := range s.lns { - if ln.fd == fd { - if len(s.loops) > 1 { - switch s.balance { - case LeastConnections: - n := atomic.LoadInt32(&l.count) - for _, lp := range s.loops { - if lp.idx != l.idx { - if atomic.LoadInt32(&lp.count) < n { - return nil // do not accept - } - } - } - case RoundRobin: - idx := int(atomic.LoadUintptr(&s.accepted)) % len(s.loops) - if idx != l.idx { - return nil // do not accept - } - atomic.AddUintptr(&s.accepted, 1) - } - } - if ln.pconn != nil { - return loopUDPRead(s, l, i, fd) - } - nfd, sa, err := syscall.Accept(fd) - if err != nil { - if err == syscall.EAGAIN { - return nil - } - return err - } - if err := syscall.SetNonblock(nfd, true); err != nil { - return err - } - c := &conn{fd: nfd, sa: sa, lnidx: i, loop: l} - l.fdconns[c.fd] = c - l.poll.AddReadWrite(c.fd) - atomic.AddInt32(&l.count, 1) - break - } - } - return nil -} - -func loopUDPRead(s *server, l *loop, lnidx, fd int) error { - n, sa, err := syscall.Recvfrom(fd, l.packet, 0) - if err != nil || n == 0 { - return nil - } - if s.events.Data != nil { - var sa6 syscall.SockaddrInet6 - switch sa := sa.(type) { - case *syscall.SockaddrInet4: - sa6.ZoneId = 0 - sa6.Port = sa.Port - for i := 0; i < 12; i++ { - sa6.Addr[i] = 0 - } - sa6.Addr[12] = sa.Addr[0] - sa6.Addr[13] = sa.Addr[1] - sa6.Addr[14] = sa.Addr[2] - sa6.Addr[15] = sa.Addr[3] - case *syscall.SockaddrInet6: - sa6 = *sa - } - c := &conn{} - c.addrIndex = lnidx - c.localAddr = s.lns[lnidx].lnaddr - c.remoteAddr = internal.SockaddrToAddr(&sa6) - in := append([]byte{}, l.packet[:n]...) - out, action := s.events.Data(c, in) - if len(out) > 0 { - if s.events.PreWrite != nil { - s.events.PreWrite() - } - syscall.Sendto(fd, out, 0, sa) - } - switch action { - case Shutdown: - return errClosing - } - } - return nil -} - -func loopOpened(s *server, l *loop, c *conn) error { - c.opened = true - c.addrIndex = c.lnidx - c.localAddr = s.lns[c.lnidx].lnaddr - c.remoteAddr = internal.SockaddrToAddr(c.sa) - if s.events.Opened != nil { - out, opts, action := s.events.Opened(c) - if len(out) > 0 { - c.out = append([]byte{}, out...) - } - c.action = action - c.reuse = opts.ReuseInputBuffer - if opts.TCPKeepAlive > 0 { - if _, ok := s.lns[c.lnidx].ln.(*net.TCPListener); ok { - internal.SetKeepAlive(c.fd, int(opts.TCPKeepAlive/time.Second)) - } - } - } - if len(c.out) == 0 && c.action == None { - l.poll.ModRead(c.fd) - } - return nil -} - -func loopWrite(s *server, l *loop, c *conn) error { - if s.events.PreWrite != nil { - s.events.PreWrite() - } - n, err := syscall.Write(c.fd, c.out) - if err != nil { - if err == syscall.EAGAIN { - return nil - } - return loopCloseConn(s, l, c, err) - } - if n == len(c.out) { - c.out = nil - } else { - c.out = c.out[n:] - } - if len(c.out) == 0 && c.action == None { - l.poll.ModRead(c.fd) - } - return nil -} - -func loopAction(s *server, l *loop, c *conn) error { - switch c.action { - default: - c.action = None - case Close: - return loopCloseConn(s, l, c, nil) - case Shutdown: - return errClosing - case Detach: - return loopDetachConn(s, l, c, nil) - } - if len(c.out) == 0 && c.action == None { - l.poll.ModRead(c.fd) - } - return nil -} - -func loopWake(s *server, l *loop, c *conn) error { - if s.events.Data == nil { - return nil - } - out, action := s.events.Data(c, nil) - c.action = action - if len(out) > 0 { - c.out = append([]byte{}, out...) - } - if len(c.out) != 0 || c.action != None { - l.poll.ModReadWrite(c.fd) - } - return nil -} - -func loopRead(s *server, l *loop, c *conn) error { - var in []byte - n, err := syscall.Read(c.fd, l.packet) - if n == 0 || err != nil { - if err == syscall.EAGAIN { - return nil - } - return loopCloseConn(s, l, c, err) - } - in = l.packet[:n] - if !c.reuse { - in = append([]byte{}, in...) - } - if s.events.Data != nil { - out, action := s.events.Data(c, in) - c.action = action - if len(out) > 0 { - c.out = append([]byte{}, out...) - } - } - if len(c.out) != 0 || c.action != None { - l.poll.ModReadWrite(c.fd) - } - return nil -} - -type detachedConn struct { - fd int -} - -func (c *detachedConn) Close() error { - err := syscall.Close(c.fd) - if err != nil { - return err - } - c.fd = -1 - return nil -} - -func (c *detachedConn) Read(p []byte) (n int, err error) { - n, err = syscall.Read(c.fd, p) - if err != nil { - return n, err - } - if n == 0 { - if len(p) == 0 { - return 0, nil - } - return 0, io.EOF - } - return n, nil -} - -func (c *detachedConn) Write(p []byte) (n int, err error) { - n = len(p) - for len(p) > 0 { - nn, err := syscall.Write(c.fd, p) - if err != nil { - return n, err - } - p = p[nn:] - } - return n, nil -} - -func (ln *listener) close() { - if ln.fd != 0 { - syscall.Close(ln.fd) - } - if ln.f != nil { - ln.f.Close() - } - if ln.ln != nil { - ln.ln.Close() - } - if ln.pconn != nil { - ln.pconn.Close() - } - if ln.network == "unix" { - os.RemoveAll(ln.addr) - } -} - -// system takes the net listener and detaches it from it's parent -// event loop, grabs the file descriptor, and makes it non-blocking. -func (ln *listener) system() error { - var err error - switch netln := ln.ln.(type) { - case nil: - switch pconn := ln.pconn.(type) { - case *net.UDPConn: - ln.f, err = pconn.File() - } - case *net.TCPListener: - ln.f, err = netln.File() - case *net.UnixListener: - ln.f, err = netln.File() - } - if err != nil { - ln.close() - return err - } - ln.fd = int(ln.f.Fd()) - return syscall.SetNonblock(ln.fd, true) -} - -func reuseportListenPacket(proto, addr string) (l net.PacketConn, err error) { - return reuseport.ListenPacket(proto, addr) -} - -func reuseportListen(proto, addr string) (l net.Listener, err error) { - return reuseport.Listen(proto, addr) -} diff --git a/vendor/github.com/tidwall/evio/examples/echo-server/main.go b/vendor/github.com/tidwall/evio/examples/echo-server/main.go deleted file mode 100644 index 27c5e0be..00000000 --- a/vendor/github.com/tidwall/evio/examples/echo-server/main.go +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright 2017 Joshua J Baker. All rights reserved. -// Use of this source code is governed by an MIT-style -// license that can be found in the LICENSE file. - -package main - -import ( - "flag" - "fmt" - "log" - "strings" - - "github.com/tidwall/evio" -) - -func main() { - var port int - var loops int - var udp bool - var trace bool - var reuseport bool - var stdlib bool - - flag.IntVar(&port, "port", 5000, "server port") - flag.BoolVar(&udp, "udp", false, "listen on udp") - flag.BoolVar(&reuseport, "reuseport", false, "reuseport (SO_REUSEPORT)") - flag.BoolVar(&trace, "trace", false, "print packets to console") - flag.IntVar(&loops, "loops", 0, "num loops") - flag.BoolVar(&stdlib, "stdlib", false, "use stdlib") - flag.Parse() - - var events evio.Events - events.NumLoops = loops - events.Serving = func(srv evio.Server) (action evio.Action) { - log.Printf("echo server started on port %d (loops: %d)", port, srv.NumLoops) - if reuseport { - log.Printf("reuseport") - } - if stdlib { - log.Printf("stdlib") - } - return - } - events.Data = func(c evio.Conn, in []byte) (out []byte, action evio.Action) { - if trace { - log.Printf("%s", strings.TrimSpace(string(in))) - } - out = in - return - } - scheme := "tcp" - if udp { - scheme = "udp" - } - if stdlib { - scheme += "-net" - } - log.Fatal(evio.Serve(events, fmt.Sprintf("%s://:%d?reuseport=%t", scheme, port, reuseport))) -} diff --git a/vendor/github.com/tidwall/evio/examples/http-server/main.go b/vendor/github.com/tidwall/evio/examples/http-server/main.go deleted file mode 100644 index cdb16384..00000000 --- a/vendor/github.com/tidwall/evio/examples/http-server/main.go +++ /dev/null @@ -1,221 +0,0 @@ -// Copyright 2017 Joshua J Baker. All rights reserved. -// Use of this source code is governed by an MIT-style -// license that can be found in the LICENSE file. - -package main - -import ( - "bytes" - "flag" - "fmt" - "log" - "os" - "strconv" - "strings" - "time" - - "github.com/tidwall/evio" -) - -var res string - -type request struct { - proto, method string - path, query string - head, body string - remoteAddr string -} - -func main() { - var port int - var loops int - var aaaa bool - var noparse bool - var unixsocket string - var stdlib bool - - flag.StringVar(&unixsocket, "unixsocket", "", "unix socket") - flag.IntVar(&port, "port", 8080, "server port") - flag.BoolVar(&aaaa, "aaaa", false, "aaaaa....") - flag.BoolVar(&noparse, "noparse", true, "do not parse requests") - flag.BoolVar(&stdlib, "stdlib", false, "use stdlib") - flag.IntVar(&loops, "loops", 0, "num loops") - flag.Parse() - - if os.Getenv("NOPARSE") == "1" { - noparse = true - } - - if aaaa { - res = strings.Repeat("a", 1024) - } else { - res = "Hello World!\r\n" - } - - var events evio.Events - events.NumLoops = loops - events.Serving = func(srv evio.Server) (action evio.Action) { - log.Printf("http server started on port %d (loops: %d)", port, srv.NumLoops) - if unixsocket != "" { - log.Printf("http server started at %s", unixsocket) - } - if stdlib { - log.Printf("stdlib") - } - return - } - - events.Opened = func(c evio.Conn) (out []byte, opts evio.Options, action evio.Action) { - c.SetContext(&evio.InputStream{}) - //log.Printf("opened: laddr: %v: raddr: %v", c.LocalAddr(), c.RemoteAddr()) - return - } - - events.Closed = func(c evio.Conn, err error) (action evio.Action) { - //log.Printf("closed: %s: %s", c.LocalAddr().String(), c.RemoteAddr().String()) - return - } - - events.Data = func(c evio.Conn, in []byte) (out []byte, action evio.Action) { - if in == nil { - return - } - is := c.Context().(*evio.InputStream) - data := is.Begin(in) - if noparse && bytes.Contains(data, []byte("\r\n\r\n")) { - // for testing minimal single packet request -> response. - out = appendresp(nil, "200 OK", "", res) - return - } - // process the pipeline - var req request - for { - leftover, err := parsereq(data, &req) - if err != nil { - // bad thing happened - out = appendresp(out, "500 Error", "", err.Error()+"\n") - action = evio.Close - break - } else if len(leftover) == len(data) { - // request not ready, yet - break - } - // handle the request - req.remoteAddr = c.RemoteAddr().String() - out = appendhandle(out, &req) - data = leftover - } - is.End(data) - return - } - var ssuf string - if stdlib { - ssuf = "-net" - } - // We at least want the single http address. - addrs := []string{fmt.Sprintf("tcp"+ssuf+"://:%d", port)} - if unixsocket != "" { - addrs = append(addrs, fmt.Sprintf("unix"+ssuf+"://%s", unixsocket)) - } - // Start serving! - log.Fatal(evio.Serve(events, addrs...)) -} - -// appendhandle handles the incoming request and appends the response to -// the provided bytes, which is then returned to the caller. -func appendhandle(b []byte, req *request) []byte { - return appendresp(b, "200 OK", "", res) -} - -// appendresp will append a valid http response to the provide bytes. -// The status param should be the code plus text such as "200 OK". -// The head parameter should be a series of lines ending with "\r\n" or empty. -func appendresp(b []byte, status, head, body string) []byte { - b = append(b, "HTTP/1.1"...) - b = append(b, ' ') - b = append(b, status...) - b = append(b, '\r', '\n') - b = append(b, "Server: evio\r\n"...) - b = append(b, "Date: "...) - b = time.Now().AppendFormat(b, "Mon, 02 Jan 2006 15:04:05 GMT") - b = append(b, '\r', '\n') - if len(body) > 0 { - b = append(b, "Content-Length: "...) - b = strconv.AppendInt(b, int64(len(body)), 10) - b = append(b, '\r', '\n') - } - b = append(b, head...) - b = append(b, '\r', '\n') - if len(body) > 0 { - b = append(b, body...) - } - return b -} - -// parsereq is a very simple http request parser. This operation -// waits for the entire payload to be buffered before returning a -// valid request. -func parsereq(data []byte, req *request) (leftover []byte, err error) { - sdata := string(data) - var i, s int - var top string - var clen int - var q = -1 - // method, path, proto line - for ; i < len(sdata); i++ { - if sdata[i] == ' ' { - req.method = sdata[s:i] - for i, s = i+1, i+1; i < len(sdata); i++ { - if sdata[i] == '?' && q == -1 { - q = i - s - } else if sdata[i] == ' ' { - if q != -1 { - req.path = sdata[s:q] - req.query = req.path[q+1 : i] - } else { - req.path = sdata[s:i] - } - for i, s = i+1, i+1; i < len(sdata); i++ { - if sdata[i] == '\n' && sdata[i-1] == '\r' { - req.proto = sdata[s:i] - i, s = i+1, i+1 - break - } - } - break - } - } - break - } - } - if req.proto == "" { - return data, fmt.Errorf("malformed request") - } - top = sdata[:s] - for ; i < len(sdata); i++ { - if i > 1 && sdata[i] == '\n' && sdata[i-1] == '\r' { - line := sdata[s : i-1] - s = i + 1 - if line == "" { - req.head = sdata[len(top)+2 : i+1] - i++ - if clen > 0 { - if len(sdata[i:]) < clen { - break - } - req.body = sdata[i : i+clen] - i += clen - } - return data[i:], nil - } - if strings.HasPrefix(line, "Content-Length:") { - n, err := strconv.ParseInt(strings.TrimSpace(line[len("Content-Length:"):]), 10, 64) - if err == nil { - clen = int(n) - } - } - } - } - // not enough data - return data, nil -} diff --git a/vendor/github.com/tidwall/evio/examples/redis-server/main.go b/vendor/github.com/tidwall/evio/examples/redis-server/main.go deleted file mode 100644 index d4eddb44..00000000 --- a/vendor/github.com/tidwall/evio/examples/redis-server/main.go +++ /dev/null @@ -1,181 +0,0 @@ -// Copyright 2017 Joshua J Baker. All rights reserved. -// Use of this source code is governed by an MIT-style -// license that can be found in the LICENSE file. - -package main - -import ( - "flag" - "fmt" - "log" - "strings" - "sync" - - "github.com/tidwall/evio" - "github.com/tidwall/redcon" -) - -type conn struct { - is evio.InputStream - addr string -} - -func main() { - var port int - var unixsocket string - var stdlib bool - var loops int - var balance string - flag.IntVar(&port, "port", 6380, "server port") - flag.IntVar(&loops, "loops", 0, "num loops") - flag.StringVar(&unixsocket, "unixsocket", "socket", "unix socket") - flag.StringVar(&balance, "balance", "random", "random, round-robin, least-connections") - flag.BoolVar(&stdlib, "stdlib", false, "use stdlib") - flag.Parse() - - var mu sync.RWMutex - var keys = make(map[string]string) - var events evio.Events - switch balance { - default: - log.Fatalf("invalid -balance flag: '%v'", balance) - case "random": - events.LoadBalance = evio.Random - case "round-robin": - events.LoadBalance = evio.RoundRobin - case "least-connections": - events.LoadBalance = evio.LeastConnections - } - events.NumLoops = loops - events.Serving = func(srv evio.Server) (action evio.Action) { - log.Printf("redis server started on port %d (loops: %d)", port, srv.NumLoops) - if unixsocket != "" { - log.Printf("redis server started at %s (loops: %d)", unixsocket, srv.NumLoops) - } - if stdlib { - log.Printf("stdlib") - } - return - } - events.Opened = func(ec evio.Conn) (out []byte, opts evio.Options, action evio.Action) { - //fmt.Printf("opened: %v\n", ec.RemoteAddr()) - ec.SetContext(&conn{}) - return - } - events.Closed = func(ec evio.Conn, err error) (action evio.Action) { - // fmt.Printf("closed: %v\n", ec.RemoteAddr()) - return - } - - events.Data = func(ec evio.Conn, in []byte) (out []byte, action evio.Action) { - if in == nil { - log.Printf("wake from %s\n", ec.RemoteAddr()) - return nil, evio.Close - } - c := ec.Context().(*conn) - data := c.is.Begin(in) - var n int - var complete bool - var err error - var args [][]byte - for action == evio.None { - complete, args, _, data, err = redcon.ReadNextCommand(data, args[:0]) - if err != nil { - action = evio.Close - out = redcon.AppendError(out, err.Error()) - break - } - if !complete { - break - } - if len(args) > 0 { - n++ - switch strings.ToUpper(string(args[0])) { - default: - out = redcon.AppendError(out, "ERR unknown command '"+string(args[0])+"'") - case "PING": - if len(args) > 2 { - out = redcon.AppendError(out, "ERR wrong number of arguments for '"+string(args[0])+"' command") - } else if len(args) == 2 { - out = redcon.AppendBulk(out, args[1]) - } else { - out = redcon.AppendString(out, "PONG") - } - case "WAKE": - go ec.Wake() - out = redcon.AppendString(out, "OK") - case "ECHO": - if len(args) != 2 { - out = redcon.AppendError(out, "ERR wrong number of arguments for '"+string(args[0])+"' command") - } else { - out = redcon.AppendBulk(out, args[1]) - } - case "SHUTDOWN": - out = redcon.AppendString(out, "OK") - action = evio.Shutdown - case "QUIT": - out = redcon.AppendString(out, "OK") - action = evio.Close - case "GET": - if len(args) != 2 { - out = redcon.AppendError(out, "ERR wrong number of arguments for '"+string(args[0])+"' command") - } else { - key := string(args[1]) - mu.Lock() - val, ok := keys[key] - mu.Unlock() - if !ok { - out = redcon.AppendNull(out) - } else { - out = redcon.AppendBulkString(out, val) - } - } - case "SET": - if len(args) != 3 { - out = redcon.AppendError(out, "ERR wrong number of arguments for '"+string(args[0])+"' command") - } else { - key, val := string(args[1]), string(args[2]) - mu.Lock() - keys[key] = val - mu.Unlock() - out = redcon.AppendString(out, "OK") - } - case "DEL": - if len(args) < 2 { - out = redcon.AppendError(out, "ERR wrong number of arguments for '"+string(args[0])+"' command") - } else { - var n int - mu.Lock() - for i := 1; i < len(args); i++ { - if _, ok := keys[string(args[i])]; ok { - n++ - delete(keys, string(args[i])) - } - } - mu.Unlock() - out = redcon.AppendInt(out, int64(n)) - } - case "FLUSHDB": - mu.Lock() - keys = make(map[string]string) - mu.Unlock() - out = redcon.AppendString(out, "OK") - } - } - } - c.is.End(data) - return - } - var ssuf string - if stdlib { - ssuf = "-net" - } - addrs := []string{fmt.Sprintf("tcp"+ssuf+"://:%d", port)} - if unixsocket != "" { - addrs = append(addrs, fmt.Sprintf("unix"+ssuf+"://%s", unixsocket)) - } - err := evio.Serve(events, addrs...) - if err != nil { - log.Fatal(err) - } -} diff --git a/vendor/github.com/tidwall/evio/internal/internal_bsd.go b/vendor/github.com/tidwall/evio/internal/internal_bsd.go deleted file mode 100644 index 5b433cd5..00000000 --- a/vendor/github.com/tidwall/evio/internal/internal_bsd.go +++ /dev/null @@ -1,125 +0,0 @@ -// Copyright 2017 Joshua J Baker. All rights reserved. -// Use of this source code is governed by a MIT-style -// license that can be found in the LICENSE file. - -// +build darwin netbsd freebsd openbsd dragonfly - -package internal - -import ( - "syscall" -) - -// Poll ... -type Poll struct { - fd int - changes []syscall.Kevent_t - notes noteQueue -} - -// OpenPoll ... -func OpenPoll() *Poll { - l := new(Poll) - p, err := syscall.Kqueue() - if err != nil { - panic(err) - } - l.fd = p - _, err = syscall.Kevent(l.fd, []syscall.Kevent_t{{ - Ident: 0, - Filter: syscall.EVFILT_USER, - Flags: syscall.EV_ADD | syscall.EV_CLEAR, - }}, nil, nil) - if err != nil { - panic(err) - } - - return l -} - -// Close ... -func (p *Poll) Close() error { - return syscall.Close(p.fd) -} - -// Trigger ... -func (p *Poll) Trigger(note interface{}) error { - p.notes.Add(note) - _, err := syscall.Kevent(p.fd, []syscall.Kevent_t{{ - Ident: 0, - Filter: syscall.EVFILT_USER, - Fflags: syscall.NOTE_TRIGGER, - }}, nil, nil) - return err -} - -// Wait ... -func (p *Poll) Wait(iter func(fd int, note interface{}) error) error { - events := make([]syscall.Kevent_t, 128) - for { - n, err := syscall.Kevent(p.fd, p.changes, events, nil) - if err != nil && err != syscall.EINTR { - return err - } - p.changes = p.changes[:0] - if err := p.notes.ForEach(func(note interface{}) error { - return iter(0, note) - }); err != nil { - return err - } - for i := 0; i < n; i++ { - if fd := int(events[i].Ident); fd != 0 { - if err := iter(fd, nil); err != nil { - return err - } - } - } - } -} - -// AddRead ... -func (p *Poll) AddRead(fd int) { - p.changes = append(p.changes, - syscall.Kevent_t{ - Ident: uint64(fd), Flags: syscall.EV_ADD, Filter: syscall.EVFILT_READ, - }, - ) -} - -// AddReadWrite ... -func (p *Poll) AddReadWrite(fd int) { - p.changes = append(p.changes, - syscall.Kevent_t{ - Ident: uint64(fd), Flags: syscall.EV_ADD, Filter: syscall.EVFILT_READ, - }, - syscall.Kevent_t{ - Ident: uint64(fd), Flags: syscall.EV_ADD, Filter: syscall.EVFILT_WRITE, - }, - ) -} - -// ModRead ... -func (p *Poll) ModRead(fd int) { - p.changes = append(p.changes, syscall.Kevent_t{ - Ident: uint64(fd), Flags: syscall.EV_DELETE, Filter: syscall.EVFILT_WRITE, - }) -} - -// ModReadWrite ... -func (p *Poll) ModReadWrite(fd int) { - p.changes = append(p.changes, syscall.Kevent_t{ - Ident: uint64(fd), Flags: syscall.EV_ADD, Filter: syscall.EVFILT_WRITE, - }) -} - -// ModDetach ... -func (p *Poll) ModDetach(fd int) { - p.changes = append(p.changes, - syscall.Kevent_t{ - Ident: uint64(fd), Flags: syscall.EV_DELETE, Filter: syscall.EVFILT_READ, - }, - syscall.Kevent_t{ - Ident: uint64(fd), Flags: syscall.EV_DELETE, Filter: syscall.EVFILT_WRITE, - }, - ) -} diff --git a/vendor/github.com/tidwall/evio/internal/internal_darwin.go b/vendor/github.com/tidwall/evio/internal/internal_darwin.go deleted file mode 100644 index 3e8fde8b..00000000 --- a/vendor/github.com/tidwall/evio/internal/internal_darwin.go +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright 2017 Joshua J Baker. All rights reserved. -// Use of this source code is governed by an MIT-style -// license that can be found in the LICENSE file. - -package internal - -import "syscall" - -// SetKeepAlive sets the keepalive for the connection -func SetKeepAlive(fd, secs int) error { - if err := syscall.SetsockoptInt(fd, syscall.SOL_SOCKET, 0x8, 1); err != nil { - return err - } - switch err := syscall.SetsockoptInt(fd, syscall.IPPROTO_TCP, 0x101, secs); err { - case nil, syscall.ENOPROTOOPT: // OS X 10.7 and earlier don't support this option - default: - return err - } - return syscall.SetsockoptInt(fd, syscall.IPPROTO_TCP, syscall.TCP_KEEPALIVE, secs) -} diff --git a/vendor/github.com/tidwall/evio/internal/internal_linux.go b/vendor/github.com/tidwall/evio/internal/internal_linux.go deleted file mode 100644 index 6bbaffa4..00000000 --- a/vendor/github.com/tidwall/evio/internal/internal_linux.go +++ /dev/null @@ -1,129 +0,0 @@ -// Copyright 2017 Joshua J Baker. All rights reserved. -// Use of this source code is governed by an MIT-style -// license that can be found in the LICENSE file. - -package internal - -import ( - "syscall" -) - -// Poll ... -type Poll struct { - fd int // epoll fd - wfd int // wake fd - notes noteQueue -} - -// OpenPoll ... -func OpenPoll() *Poll { - l := new(Poll) - p, err := syscall.EpollCreate1(0) - if err != nil { - panic(err) - } - l.fd = p - r0, _, e0 := syscall.Syscall(syscall.SYS_EVENTFD2, 0, 0, 0) - if e0 != 0 { - syscall.Close(p) - panic(err) - } - l.wfd = int(r0) - l.AddRead(l.wfd) - return l -} - -// Close ... -func (p *Poll) Close() error { - if err := syscall.Close(p.wfd); err != nil { - return err - } - return syscall.Close(p.fd) -} - -// Trigger ... -func (p *Poll) Trigger(note interface{}) error { - p.notes.Add(note) - _, err := syscall.Write(p.wfd, []byte{0, 0, 0, 0, 0, 0, 0, 1}) - return err -} - -// Wait ... -func (p *Poll) Wait(iter func(fd int, note interface{}) error) error { - events := make([]syscall.EpollEvent, 64) - for { - n, err := syscall.EpollWait(p.fd, events, -1) - if err != nil && err != syscall.EINTR { - return err - } - if err := p.notes.ForEach(func(note interface{}) error { - return iter(0, note) - }); err != nil { - return err - } - for i := 0; i < n; i++ { - if fd := int(events[i].Fd); fd != p.wfd { - if err := iter(fd, nil); err != nil { - return err - } - } else { - - } - } - } -} - -// AddReadWrite ... -func (p *Poll) AddReadWrite(fd int) { - if err := syscall.EpollCtl(p.fd, syscall.EPOLL_CTL_ADD, fd, - &syscall.EpollEvent{Fd: int32(fd), - Events: syscall.EPOLLIN | syscall.EPOLLOUT, - }, - ); err != nil { - panic(err) - } -} - -// AddRead ... -func (p *Poll) AddRead(fd int) { - if err := syscall.EpollCtl(p.fd, syscall.EPOLL_CTL_ADD, fd, - &syscall.EpollEvent{Fd: int32(fd), - Events: syscall.EPOLLIN, - }, - ); err != nil { - panic(err) - } -} - -// ModRead ... -func (p *Poll) ModRead(fd int) { - if err := syscall.EpollCtl(p.fd, syscall.EPOLL_CTL_MOD, fd, - &syscall.EpollEvent{Fd: int32(fd), - Events: syscall.EPOLLIN, - }, - ); err != nil { - panic(err) - } -} - -// ModReadWrite ... -func (p *Poll) ModReadWrite(fd int) { - if err := syscall.EpollCtl(p.fd, syscall.EPOLL_CTL_MOD, fd, - &syscall.EpollEvent{Fd: int32(fd), - Events: syscall.EPOLLIN | syscall.EPOLLOUT, - }, - ); err != nil { - panic(err) - } -} - -// ModDetach ... -func (p *Poll) ModDetach(fd int) { - if err := syscall.EpollCtl(p.fd, syscall.EPOLL_CTL_DEL, fd, - &syscall.EpollEvent{Fd: int32(fd), - Events: syscall.EPOLLIN | syscall.EPOLLOUT, - }, - ); err != nil { - panic(err) - } -} diff --git a/vendor/github.com/tidwall/evio/internal/internal_openbsd.go b/vendor/github.com/tidwall/evio/internal/internal_openbsd.go deleted file mode 100644 index 8ea7edbd..00000000 --- a/vendor/github.com/tidwall/evio/internal/internal_openbsd.go +++ /dev/null @@ -1,11 +0,0 @@ -// Copyright 2017 Joshua J Baker. All rights reserved. -// Use of this source code is governed by an MIT-style -// license that can be found in the LICENSE file. - -package internal - -// SetKeepAlive sets the keepalive for the connection -func SetKeepAlive(fd, secs int) error { - // OpenBSD has no user-settable per-socket TCP keepalive options. - return nil -} diff --git a/vendor/github.com/tidwall/evio/internal/internal_unix.go b/vendor/github.com/tidwall/evio/internal/internal_unix.go deleted file mode 100644 index ddd386a6..00000000 --- a/vendor/github.com/tidwall/evio/internal/internal_unix.go +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright 2017 Joshua J Baker. All rights reserved. -// Use of this source code is governed by an MIT-style -// license that can be found in the LICENSE file. - -// +build netbsd freebsd dragonfly linux - -package internal - -import "syscall" - -func SetKeepAlive(fd, secs int) error { - if err := syscall.SetsockoptInt(fd, syscall.SOL_SOCKET, syscall.SO_KEEPALIVE, 1); err != nil { - return err - } - if err := syscall.SetsockoptInt(fd, syscall.IPPROTO_TCP, syscall.TCP_KEEPINTVL, secs); err != nil { - return err - } - return syscall.SetsockoptInt(fd, syscall.IPPROTO_TCP, syscall.TCP_KEEPIDLE, secs) -} diff --git a/vendor/github.com/tidwall/evio/internal/notequeue.go b/vendor/github.com/tidwall/evio/internal/notequeue.go deleted file mode 100644 index 29cf2bc7..00000000 --- a/vendor/github.com/tidwall/evio/internal/notequeue.go +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright 2018 Joshua J Baker. All rights reserved. -// Use of this source code is governed by an MIT-style -// license that can be found in the LICENSE file. - -package internal - -import ( - "runtime" - "sync/atomic" -) - -// this is a good candiate for a lock-free structure. - -type spinlock struct{ lock uintptr } - -func (l *spinlock) Lock() { - for !atomic.CompareAndSwapUintptr(&l.lock, 0, 1) { - runtime.Gosched() - } -} -func (l *spinlock) Unlock() { - atomic.StoreUintptr(&l.lock, 0) -} - -type noteQueue struct { - mu spinlock - notes []interface{} -} - -func (q *noteQueue) Add(note interface{}) (one bool) { - q.mu.Lock() - q.notes = append(q.notes, note) - n := len(q.notes) - q.mu.Unlock() - return n == 1 -} - -func (q *noteQueue) ForEach(iter func(note interface{}) error) error { - q.mu.Lock() - if len(q.notes) == 0 { - q.mu.Unlock() - return nil - } - notes := q.notes - q.notes = nil - q.mu.Unlock() - for _, note := range notes { - if err := iter(note); err != nil { - return err - } - } - return nil -} diff --git a/vendor/github.com/tidwall/evio/internal/socktoaddr.go b/vendor/github.com/tidwall/evio/internal/socktoaddr.go deleted file mode 100644 index 9e9425c6..00000000 --- a/vendor/github.com/tidwall/evio/internal/socktoaddr.go +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright 2018 Joshua J Baker. All rights reserved. -// Use of this source code is governed by an MIT-style -// license that can be found in the LICENSE file. - -package internal - -import ( - "net" - "syscall" -) - -// SockaddrToAddr returns a go/net friendly address -func SockaddrToAddr(sa syscall.Sockaddr) net.Addr { - var a net.Addr - switch sa := sa.(type) { - case *syscall.SockaddrInet4: - a = &net.TCPAddr{ - IP: append([]byte{}, sa.Addr[:]...), - Port: sa.Port, - } - case *syscall.SockaddrInet6: - var zone string - if sa.ZoneId != 0 { - if ifi, err := net.InterfaceByIndex(int(sa.ZoneId)); err == nil { - zone = ifi.Name - } - } - if zone == "" && sa.ZoneId != 0 { - } - a = &net.TCPAddr{ - IP: append([]byte{}, sa.Addr[:]...), - Port: sa.Port, - Zone: zone, - } - case *syscall.SockaddrUnix: - a = &net.UnixAddr{Net: "unix", Name: sa.Name} - } - return a -} diff --git a/vendor/github.com/tidwall/evio/logo.png b/vendor/github.com/tidwall/evio/logo.png deleted file mode 100644 index e5be817dc9db6aad61777196a3c0105caf442b1b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 25681 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