From 933f243c6c1efb7387470cc5fea63a9af0a55d47 Mon Sep 17 00:00:00 2001 From: tidwall Date: Mon, 5 Nov 2018 15:24:45 -0700 Subject: [PATCH 01/16] Code cleanup --- cmd/tile38-server/main.go | 4 +- internal/server/server.go | 189 +++++++++++++++++++++++++++++++++++++- 2 files changed, 190 insertions(+), 3 deletions(-) diff --git a/cmd/tile38-server/main.go b/cmd/tile38-server/main.go index 784657e6..20658aea 100644 --- a/cmd/tile38-server/main.go +++ b/cmd/tile38-server/main.go @@ -35,7 +35,7 @@ var ( ) // TODO: Set to false in 2.* -var httpTransport bool = true +var httpTransport = true // Fire up a webhook test server by using the --webhook-http-consumer-port // for example @@ -47,7 +47,7 @@ var httpTransport bool = true type hserver struct{} func (s *hserver) Send(ctx context.Context, in *hservice.MessageRequest) (*hservice.MessageReply, error) { - return &hservice.MessageReply{true}, nil + return &hservice.MessageReply{Ok: true}, nil } func main() { diff --git a/internal/server/server.go b/internal/server/server.go index fdd0cb09..7915b595 100644 --- a/internal/server/server.go +++ b/internal/server/server.go @@ -36,6 +36,8 @@ import ( "github.com/tidwall/tile38/internal/log" ) +const useEvio = false + var errOOM = errors.New("OOM command not allowed when used memory > 'maxmemory'") const goingLive = "going live" @@ -270,7 +272,10 @@ func Serve(host string, port int, dir string, http bool) error { }() // Start the network server - return server.evioServe() + if useEvio { + return server.evioServe() + } + return server.netServe() } func (server *Server) isProtected() bool { @@ -481,6 +486,188 @@ func (server *Server) evioServe() error { 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 { + return err + } + defer ln.Close() + log.Infof("Ready to accept connections at %s", ln.Addr()) + var clientID int64 + for { + conn, err := ln.Accept() + if err != nil { + return err + } + + go func(conn net.Conn) { + // open connection + // create the client + client := new(Client) + client.id = int(atomic.AddInt64(&clientID, 1)) + client.opened = time.Now() + client.remoteAddr = conn.RemoteAddr().String() + + // 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 { + if conn, ok := conn.(*net.TCPConn); ok { + conn.SetKeepAlive(true) + conn.SetKeepAlivePeriod( + time.Duration(server.config.keepAlive()) * time.Second, + ) + } + } + log.Debugf("Opened connection: %s", client.remoteAddr) + + defer func() { + // close connection + // delete from server map + server.connsmu.Lock() + delete(server.conns, client.id) + server.connsmu.Unlock() + log.Debugf("Closed connection: %s", client.remoteAddr) + conn.Close() + }() + + // 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. + conn.Write(deniedMessage) + return // close connection + } + } + packet := make([]byte, 0xFFFF) + for { + var close bool + n, err := conn.Read(packet) + if err != nil { + return + } + in := packet[:n] + + // 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) + return // close connection + } + 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) { + close = true // close connection + 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") + } + close = true // close connection + 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 + // detach + var rwc io.ReadWriteCloser = conn + client.conn = rwc + if len(client.out) > 0 { + client.conn.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) + + var wg sync.WaitGroup + wg.Add(1) + go func() { + defer wg.Done() + err := server.goLive( + client.goLiveErr, + &liveConn{conn.RemoteAddr(), rwc}, + &client.pr, + client.goLiveMsg, + client.goLiveMsg.ConnType == WebSocket, + ) + if err != nil { + log.Error(err) + } + }() + wg.Wait() + return // close connection + } + log.Error(err) + return // close connection, NOW + } + + client.outputType = msg.OutputType + } else { + client.Write([]byte("HTTP/1.1 500 Bad Request\r\nConnection: close\r\n\r\n")) + break + } + if msg.ConnType == HTTP || msg.ConnType == WebSocket { + close = true // close connection + break + } + } + + packet = packet[len(packet)-rdbuf.Len():] + client.in.End(packet) + + // write to client + if len(client.out) > 0 { + func() { + // prewrite + server.mu.Lock() + defer server.mu.Unlock() + server.flushAOF() + }() + conn.Write(client.out) + client.out = client.out[:0] + } + if close { + break + } + } + }(conn) + } +} + type liveConn struct { remoteAddr net.Addr rwc io.ReadWriteCloser From 161c6faff94fa8c2b92258435401a1cacd2eb5e8 Mon Sep 17 00:00:00 2001 From: tidwall Date: Mon, 5 Nov 2018 15:58:43 -0700 Subject: [PATCH 02/16] Added evio flag --- cmd/tile38-server/main.go | 23 +++++++++++++++++++---- core/options.go | 7 +++++-- core/version.go | 1 + internal/server/server.go | 8 +++----- 4 files changed, 28 insertions(+), 11 deletions(-) diff --git a/cmd/tile38-server/main.go b/cmd/tile38-server/main.go index 20658aea..de876dfd 100644 --- a/cmd/tile38-server/main.go +++ b/cmd/tile38-server/main.go @@ -80,6 +80,7 @@ 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) Developer Options: --dev : enable developer mode @@ -146,10 +147,10 @@ Developer Options: if i < len(os.Args) { switch strings.ToLower(os.Args[i]) { case "no": - core.ProtectedMode = "no" + core.ProtectedMode = false continue case "yes": - core.ProtectedMode = "yes" + core.ProtectedMode = true continue } } @@ -163,10 +164,10 @@ Developer Options: if i < len(os.Args) { switch strings.ToLower(os.Args[i]) { case "no": - core.AppendOnly = "no" + core.AppendOnly = false continue case "yes": - core.AppendOnly = "yes" + core.AppendOnly = true continue } } @@ -213,6 +214,20 @@ Developer Options: } fmt.Fprintf(os.Stderr, "http-transport must be 'yes' or 'no'\n") os.Exit(1) + case "--evio", "-evio": + i++ + if i < len(os.Args) { + switch strings.ToLower(os.Args[i]) { + case "no": + core.Evio = false + continue + case "yes": + core.Evio = true + continue + } + } + fmt.Fprintf(os.Stderr, "evio must be 'yes' or 'no'\n") + os.Exit(1) } nargs = append(nargs, os.Args[i]) } diff --git a/core/options.go b/core/options.go index 76172062..97776727 100644 --- a/core/options.go +++ b/core/options.go @@ -7,10 +7,10 @@ var DevMode = false var ShowDebugMessages = false // ProtectedMode forces Tile38 to default in protected mode. -var ProtectedMode = "yes" +var ProtectedMode = true // AppendOnly allows for disabling the appendonly file. -var AppendOnly = "yes" +var AppendOnly = true // AppendFileName allows for custom appendonly file path var AppendFileName string @@ -20,3 +20,6 @@ var QueueFileName string // 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/core/version.go b/core/version.go index 70a0e018..708d09a4 100644 --- a/core/version.go +++ b/core/version.go @@ -1,5 +1,6 @@ package core +// Build variables var ( Version = "0.0.0" // Placeholder for the version BuildTime = "" // Placeholder for the build time diff --git a/internal/server/server.go b/internal/server/server.go index 7915b595..546209e6 100644 --- a/internal/server/server.go +++ b/internal/server/server.go @@ -36,8 +36,6 @@ import ( "github.com/tidwall/tile38/internal/log" ) -const useEvio = false - var errOOM = errors.New("OOM command not allowed when used memory > 'maxmemory'") const goingLive = "going live" @@ -237,7 +235,7 @@ func Serve(host string, port int, dir string, http bool) error { if err := server.migrateAOF(); err != nil { return err } - if core.AppendOnly == "yes" { + if core.AppendOnly == true { f, err := os.OpenFile(core.AppendFileName, os.O_CREATE|os.O_RDWR, 0600) if err != nil { return err @@ -272,14 +270,14 @@ func Serve(host string, port int, dir string, http bool) error { }() // Start the network server - if useEvio { + if core.Evio { return server.evioServe() } return server.netServe() } func (server *Server) isProtected() bool { - if core.ProtectedMode == "no" { + if core.ProtectedMode == false { // --protected-mode no return false } From edf5d22095e4dca2697baf5eb38f41f2b694591f Mon Sep 17 00:00:00 2001 From: tidwall Date: Mon, 5 Nov 2018 17:28:26 -0700 Subject: [PATCH 03/16] Hack geojson circle.go --- vendor/github.com/tidwall/geojson/circle.go | 99 ++++++++++++++++----- 1 file changed, 75 insertions(+), 24 deletions(-) diff --git a/vendor/github.com/tidwall/geojson/circle.go b/vendor/github.com/tidwall/geojson/circle.go index 277766f0..7d4876bb 100644 --- a/vendor/github.com/tidwall/geojson/circle.go +++ b/vendor/github.com/tidwall/geojson/circle.go @@ -2,6 +2,8 @@ package geojson import ( "strconv" + "sync/atomic" + "unsafe" "github.com/tidwall/geojson/geo" "github.com/tidwall/geojson/geometry" @@ -9,7 +11,7 @@ import ( // Circle ... type Circle struct { - Object + object *Object center geometry.Point meters float64 haversine float64 @@ -27,27 +29,6 @@ func NewCircle(center geometry.Point, meters float64, steps int) *Circle { g.center = center g.meters = meters g.steps = steps - if meters <= 0 { - g.Object = NewPoint(center) - } else { - meters = geo.NormalizeDistance(meters) - var points []geometry.Point - step := 360.0 / float64(steps) - i := 0 - for deg := 360.0; deg > 0; deg -= step { - lat, lon := geo.DestinationPoint(center.Y, center.X, meters, deg) - points = append(points, geometry.Point{X: lon, Y: lat}) - i++ - } - // TODO: account for the pole and antimerdian. In most cases only a - // polygon is needed, but when the circle bounds passes the 90/180 - // lines, we need to create a multipolygon - points = append(points, points[0]) - g.Object = NewPolygon( - geometry.NewPoly(points, nil, geometry.DefaultIndexOptions), - ) - g.haversine = geo.DistanceToHaversine(meters) - } return g } @@ -128,7 +109,7 @@ func (g *Circle) Contains(obj Object) bool { return true default: // No simple cases, so using polygon approximation. - return g.Object.Contains(other) + return g.getObject().Contains(other) } } @@ -185,6 +166,76 @@ func (g *Circle) Intersects(obj Object) bool { return false default: // No simple cases, so using polygon approximation. - return g.Object.Intersects(obj) + return g.getObject().Intersects(obj) } } + +// Empty ... +func (g *Circle) Empty() bool { + return false +} + +// ForEach ... +func (g *Circle) ForEach(iter func(geom Object) bool) bool { + return iter(g) +} + +// NumPoints ... +func (g *Circle) NumPoints() int { + return 1 +} + +// Distance ... +func (g *Circle) Distance(other Object) float64 { + return g.getObject().Distance(other) +} + +// Rect ... +func (g *Circle) Rect() geometry.Rect { + return g.getObject().Rect() +} + +// Spatial ... +func (g *Circle) Spatial() Spatial { + return g.getObject().Spatial() +} + +func (g *Circle) getObject() Object { + for { + object := (*Object)(atomic.LoadPointer( + (*unsafe.Pointer)(unsafe.Pointer(&g.object))), + ) + if object != nil { + return *object + } + newObject := makeCircleObject(g.center, g.meters, g.steps) + if atomic.CompareAndSwapPointer( + (*unsafe.Pointer)(unsafe.Pointer(&g.object)), + nil, unsafe.Pointer(&newObject), + ) { + return *object + } + } +} + +func makeCircleObject(center geometry.Point, meters float64, steps int) Object { + if meters <= 0 { + return NewPoint(center) + } + meters = geo.NormalizeDistance(meters) + var points []geometry.Point + step := 360.0 / float64(steps) + i := 0 + for deg := 360.0; deg > 0; deg -= step { + lat, lon := geo.DestinationPoint(center.Y, center.X, meters, deg) + points = append(points, geometry.Point{X: lon, Y: lat}) + i++ + } + // TODO: account for the pole and antimerdian. In most cases only a + // polygon is needed, but when the circle bounds passes the 90/180 + // lines, we need to create a multipolygon + points = append(points, points[0]) + return NewPolygon( + geometry.NewPoly(points, nil, geometry.DefaultIndexOptions), + ) +} From 372744b192beb9b609ec28d43124614e22a1bf01 Mon Sep 17 00:00:00 2001 From: tidwall Date: Tue, 6 Nov 2018 03:40:52 -0700 Subject: [PATCH 04/16] More hacking vendored circle.go --- cmd/tile38-benchmark/main.go | 52 ++++++++++-- internal/collection/collection.go | 25 ++++++ vendor/github.com/tidwall/geojson/circle.go | 26 +++--- vendor/github.com/tidwall/geojson/geo/geo.go | 83 +++++++++++++++++++- vendor/github.com/tidwall/geojson/rect.go | 4 +- 5 files changed, 163 insertions(+), 27 deletions(-) diff --git a/cmd/tile38-benchmark/main.go b/cmd/tile38-benchmark/main.go index 772568cc..49e93d89 100644 --- a/cmd/tile38-benchmark/main.go +++ b/cmd/tile38-benchmark/main.go @@ -23,7 +23,7 @@ var ( pipeline = 1 csv = false json = false - tests = "PING,SET,GET,SEARCH,EVAL" + tests = "PING,SET,GET,INTERSECTS,WITHIN,NEARBY,EVAL" redis = false ) @@ -270,36 +270,72 @@ func main() { }, ) } - case "SEARCH": + case "INTERSECTS": if !redis { - redbench.Bench("SEARCH (nearby 1km)", addr, opts, prepFn, + + redbench.Bench("INTERSECTS (intersects-circle 1km)", addr, opts, prepFn, func(buf []byte) []byte { lat, lon := randPoint() - return redbench.AppendCommand(buf, "NEARBY", "key:bench", "COUNT", "POINT", + return redbench.AppendCommand(buf, + "INTERSECTS", "key:bench", "COUNT", "CIRCLE", strconv.FormatFloat(lat, 'f', 5, 64), strconv.FormatFloat(lon, 'f', 5, 64), "1000") }, ) - redbench.Bench("SEARCH (nearby 10km)", addr, opts, prepFn, + redbench.Bench("INTERSECTS (intersects-circle 10km)", addr, opts, prepFn, func(buf []byte) []byte { lat, lon := randPoint() - return redbench.AppendCommand(buf, "NEARBY", "key:bench", "COUNT", "POINT", + return redbench.AppendCommand(buf, + "INTERSECTS", "key:bench", "COUNT", "CIRCLE", strconv.FormatFloat(lat, 'f', 5, 64), strconv.FormatFloat(lon, 'f', 5, 64), "10000") }, ) - redbench.Bench("SEARCH (nearby 100km)", addr, opts, prepFn, + redbench.Bench("INTERSECTS (intersects-circle 100km)", addr, opts, prepFn, func(buf []byte) []byte { lat, lon := randPoint() - return redbench.AppendCommand(buf, "NEARBY", "key:bench", "COUNT", "POINT", + return redbench.AppendCommand(buf, + "INTERSECTS", "key:bench", "COUNT", "CIRCLE", strconv.FormatFloat(lat, 'f', 5, 64), strconv.FormatFloat(lon, 'f', 5, 64), "100000") }, ) } + case "NEARBY": + if !redis { + redbench.Bench("NEARBY (limit 1)", addr, opts, prepFn, + func(buf []byte) []byte { + lat, lon := randPoint() + return redbench.AppendCommand(buf, + "NEARBY", "key:bench", "LIMIT", "1", "COUNT", "POINT", + strconv.FormatFloat(lat, 'f', 5, 64), + strconv.FormatFloat(lon, 'f', 5, 64), + ) + }, + ) + redbench.Bench("NEARBY (limit 10)", addr, opts, prepFn, + func(buf []byte) []byte { + lat, lon := randPoint() + return redbench.AppendCommand(buf, + "NEARBY", "key:bench", "LIMIT", "10", "COUNT", "POINT", + strconv.FormatFloat(lat, 'f', 5, 64), + strconv.FormatFloat(lon, 'f', 5, 64), + ) + }, + ) + redbench.Bench("NEARBY (limit 100)", addr, opts, prepFn, + func(buf []byte) []byte { + lat, lon := randPoint() + return redbench.AppendCommand(buf, + "NEARBY", "key:bench", "LIMIT", "100", "COUNT", "POINT", + strconv.FormatFloat(lat, 'f', 5, 64), + strconv.FormatFloat(lon, 'f', 5, 64)) + }, + ) + } case "EVAL": if !redis { var i int64 diff --git a/internal/collection/collection.go b/internal/collection/collection.go index 1063f37b..ed8555ce 100644 --- a/internal/collection/collection.go +++ b/internal/collection/collection.go @@ -4,6 +4,7 @@ import ( "github.com/tidwall/boxtree/d2" "github.com/tidwall/btree" "github.com/tidwall/geojson" + "github.com/tidwall/geojson/geo" "github.com/tidwall/geojson/geometry" "github.com/tidwall/tile38/internal/ds" ) @@ -673,6 +674,30 @@ func (c *Collection) Nearby( cursor Cursor, iter func(id string, obj geojson.Object, fields []float64) bool, ) bool { + + if circle, ok := target.(*geojson.Circle); ok { + + meters := circle.Meters() + if meters > 0 { + center := circle.Center() + minLat, minLon, maxLat, maxLon := + geo.RectFromCenter(center.Y, center.X, meters) + var exists bool + c.index.Search( + []float64{minLon, minLat}, + []float64{maxLon, maxLat}, + func(_, _ []float64, itemv interface{}) bool { + exists = true + return false + }, + ) + if !exists { + return true + } + return true + } + } + alive := true center := target.Center() var count uint64 diff --git a/vendor/github.com/tidwall/geojson/circle.go b/vendor/github.com/tidwall/geojson/circle.go index 7d4876bb..3cdd8492 100644 --- a/vendor/github.com/tidwall/geojson/circle.go +++ b/vendor/github.com/tidwall/geojson/circle.go @@ -2,8 +2,6 @@ package geojson import ( "strconv" - "sync/atomic" - "unsafe" "github.com/tidwall/geojson/geo" "github.com/tidwall/geojson/geometry" @@ -11,7 +9,7 @@ import ( // Circle ... type Circle struct { - object *Object + object Object center geometry.Point meters float64 haversine float64 @@ -29,6 +27,10 @@ func NewCircle(center geometry.Point, meters float64, steps int) *Circle { g.center = center g.meters = meters g.steps = steps + if meters > 0 { + meters = geo.NormalizeDistance(meters) + g.haversine = geo.DistanceToHaversine(meters) + } return g } @@ -182,6 +184,7 @@ func (g *Circle) ForEach(iter func(geom Object) bool) bool { // NumPoints ... func (g *Circle) NumPoints() int { + // should this be g.steps? return 1 } @@ -201,21 +204,10 @@ func (g *Circle) Spatial() Spatial { } func (g *Circle) getObject() Object { - for { - object := (*Object)(atomic.LoadPointer( - (*unsafe.Pointer)(unsafe.Pointer(&g.object))), - ) - if object != nil { - return *object - } - newObject := makeCircleObject(g.center, g.meters, g.steps) - if atomic.CompareAndSwapPointer( - (*unsafe.Pointer)(unsafe.Pointer(&g.object)), - nil, unsafe.Pointer(&newObject), - ) { - return *object - } + if g.object != nil { + return g.object } + return makeCircleObject(g.center, g.meters, g.steps) } func makeCircleObject(center geometry.Point, meters float64, steps int) Object { diff --git a/vendor/github.com/tidwall/geojson/geo/geo.go b/vendor/github.com/tidwall/geojson/geo/geo.go index d82fc9a3..fe5c497e 100644 --- a/vendor/github.com/tidwall/geojson/geo/geo.go +++ b/vendor/github.com/tidwall/geojson/geo/geo.go @@ -45,7 +45,7 @@ func DistanceToHaversine(meters float64) float64 { return sin * sin } -// DistanceFromHaversine... +// DistanceFromHaversine ... func DistanceFromHaversine(haversine float64) float64 { return earthRadius * 2 * math.Asin(math.Sqrt(haversine)) } @@ -88,3 +88,84 @@ func BearingTo(latA, lonA, latB, lonB float64) float64 { return math.Mod(θ*degrees+360, 360) } + +// RectFromCenter calculates the bounding box surrounding a circle. +func RectFromCenter(lat, lon, meters float64) ( + minLat, minLon, maxLat, maxLon float64, +) { + + // see http://janmatuschek.de/LatitudeLongitudeBoundingCoordinates#Latitude + lat *= radians + lon *= radians + + r := meters / earthRadius // angular radius + + minLat = lat - r + maxLat = lat + r + + latT := math.Asin(math.Sin(lat) / math.Cos(r)) + lonΔ := math.Acos((math.Cos(r) - math.Sin(latT)*math.Sin(lat)) / (math.Cos(latT) * math.Cos(lat))) + + minLon = lon - lonΔ + maxLon = lon + lonΔ + + // Adjust for north poll + if maxLat > math.Pi/2 { + minLon = -math.Pi + maxLat = math.Pi / 2 + maxLon = math.Pi + } + + // Adjust for south poll + if minLat < -math.Pi/2 { + minLat = -math.Pi / 2 + minLon = -math.Pi + maxLon = math.Pi + } + + // Adjust for wraparound. Remove this if the commented-out condition below this block is added. + if minLon < -math.Pi || maxLon > math.Pi { + minLon = -math.Pi + maxLon = math.Pi + } + + /* + // Consider splitting area into two bboxes, using the below checks, and erasing above block for performance. See http://janmatuschek.de/LatitudeLongitudeBoundingCoordinates#PolesAnd180thMeridian + // Adjust for wraparound if minimum longitude is less than -180 degrees. + if lonMin < -math.Pi { + // box 1: + latMin = latMin + latMax = latMax + lonMin += 2*math.Pi + lonMax = math.Pi + // box 2: + latMin = latMin + latMax = latMax + lonMin = -math.Pi + lonMax = lonMax + } + // Adjust for wraparound if maximum longitude is greater than 180 degrees. + if lonMax > math.Pi { + // box 1: + latMin = latMin + latMax = latMax + lonMin = lonMin + lonMax = -math.Pi + // box 2: + latMin = latMin + latMax = latMax + lonMin = -math.Pi + lonMax -= 2*math.Pi + } + */ + + minLon = math.Mod(minLon+3*math.Pi, 2*math.Pi) - math.Pi // normalise to -180..+180° + maxLon = math.Mod(maxLon+3*math.Pi, 2*math.Pi) - math.Pi + + minLat *= degrees + minLon *= degrees + maxLat *= degrees + maxLon *= degrees + return + +} diff --git a/vendor/github.com/tidwall/geojson/rect.go b/vendor/github.com/tidwall/geojson/rect.go index 04b593a6..5a11286e 100644 --- a/vendor/github.com/tidwall/geojson/rect.go +++ b/vendor/github.com/tidwall/geojson/rect.go @@ -1,6 +1,8 @@ package geojson -import "github.com/tidwall/geojson/geometry" +import ( + "github.com/tidwall/geojson/geometry" +) // Rect ... type Rect struct { From 44edf52f97903f7ae6099bc6b1735e9f81382448 Mon Sep 17 00:00:00 2001 From: tidwall Date: Sun, 11 Nov 2018 09:05:11 -0700 Subject: [PATCH 05/16] Updated benchmark tool --- Gopkg.lock | 4 +- cmd/tile38-benchmark/main.go | 247 +++++++++++++++++++- vendor/github.com/tidwall/redbench/bench.go | 7 +- 3 files changed, 242 insertions(+), 16 deletions(-) diff --git a/Gopkg.lock b/Gopkg.lock index ec4fd9de..6eb3854d 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -295,11 +295,11 @@ [[projects]] branch = "master" - digest = "1:630381558bc538e831db8468dd0dc2702d81789f79b8ddf665eeebc729e2a055" + digest = "1:e84d0aa788bd55e938ebbaa62782385ca4da00b63c1d6bf23270c031a2ae9a88" name = "github.com/tidwall/redbench" packages = ["."] pruneopts = "" - revision = "637a608ebec1acbf049c2e4a5eda6c2d72aa3af1" + revision = "17c5b5b864a4b072481036ac689913156f5bb81c" [[projects]] branch = "master" diff --git a/cmd/tile38-benchmark/main.go b/cmd/tile38-benchmark/main.go index 49e93d89..86550b41 100644 --- a/cmd/tile38-benchmark/main.go +++ b/cmd/tile38-benchmark/main.go @@ -2,6 +2,7 @@ package main import ( "fmt" + "math" "math/rand" "net" "os" @@ -146,15 +147,23 @@ func randPoint() (lat, lon float64) { return rand.Float64()*180 - 90, rand.Float64()*360 - 180 } -func randRect() (minlat, minlon, maxlat, maxlon float64) { +func isValidRect(minlat, minlon, maxlat, maxlon float64) bool { + return minlat > -90 && maxlat < 90 && minlon > -180 && maxlon < 180 +} + +func randRect(meters float64) (minlat, minlon, maxlat, maxlon float64) { for { - minlat, minlon = randPoint() - maxlat, maxlon = minlat+1, minlon+1 - if maxlat <= 180 && maxlon <= 180 { + lat, lon := randPoint() + maxlat, _ = destinationPoint(lat, lon, meters, 0) + _, maxlon = destinationPoint(lat, lon, meters, 90) + minlat, _ = destinationPoint(lat, lon, meters, 180) + _, minlon = destinationPoint(lat, lon, meters, 270) + if isValidRect(minlat, minlon, maxlat, maxlon) { return } } } + func prepFn(conn net.Conn) bool { if json { conn.Write([]byte("output json\r\n")) @@ -222,7 +231,7 @@ func main() { redbench.Bench("SET (rect)", addr, opts, prepFn, func(buf []byte) []byte { i := atomic.AddInt64(&i, 1) - minlat, minlon, maxlat, maxlon := randRect() + minlat, minlon, maxlat, maxlon := randRect(10000) return redbench.AppendCommand(buf, "SET", "key:bench", "id:"+strconv.FormatInt(i, 10), "BOUNDS", strconv.FormatFloat(minlat, 'f', 5, 64), strconv.FormatFloat(minlon, 'f', 5, 64), @@ -270,9 +279,14 @@ func main() { }, ) } - case "INTERSECTS": - if !redis { - + case "INTERSECTS", + "INTERSECTS-RECT", "INTERSECTS-RECT-1000", "INTERSECTS-RECT-10000", "INTERSECTS-RECT-100000", + "INTERSECTS-CIRCLE", "INTERSECTS-CIRCLE-1000", "INTERSECTS-CIRCLE-10000", "INTERSECTS-CIRCLE-100000": + if redis { + break + } + switch strings.ToUpper(strings.TrimSpace(test)) { + case "INTERSECTS", "INTERSECTS-CIRCLE", "INTERSECTS-CIRCLE-1000": redbench.Bench("INTERSECTS (intersects-circle 1km)", addr, opts, prepFn, func(buf []byte) []byte { lat, lon := randPoint() @@ -283,6 +297,9 @@ func main() { "1000") }, ) + } + switch strings.ToUpper(strings.TrimSpace(test)) { + case "INTERSECTS", "INTERSECTS-CIRCLE", "INTERSECTS-CIRCLE-10000": redbench.Bench("INTERSECTS (intersects-circle 10km)", addr, opts, prepFn, func(buf []byte) []byte { lat, lon := randPoint() @@ -293,6 +310,9 @@ func main() { "10000") }, ) + } + switch strings.ToUpper(strings.TrimSpace(test)) { + case "INTERSECTS", "INTERSECTS-CIRCLE", "INTERSECTS-CIRCLE-100000": redbench.Bench("INTERSECTS (intersects-circle 100km)", addr, opts, prepFn, func(buf []byte) []byte { lat, lon := randPoint() @@ -304,8 +324,146 @@ func main() { }, ) } - case "NEARBY": - if !redis { + // INTERSECTS-BOUNDS + switch strings.ToUpper(strings.TrimSpace(test)) { + case "INTERSECTS", "INTERSECTS-BOUNDS", "INTERSECTS-BOUNDS-1000": + minlat, minlon, maxlat, maxlon := randRect(1000) + redbench.Bench("INTERSECTS (intersects-bounds 1km)", addr, opts, prepFn, + func(buf []byte) []byte { + return redbench.AppendCommand(buf, + "INTERSECTS", "key:bench", "COUNT", "BOUNDS", + strconv.FormatFloat(minlat, 'f', 5, 64), + strconv.FormatFloat(minlon, 'f', 5, 64), + strconv.FormatFloat(maxlat, 'f', 5, 64), + strconv.FormatFloat(maxlon, 'f', 5, 64)) + }, + ) + } + switch strings.ToUpper(strings.TrimSpace(test)) { + case "INTERSECTS", "INTERSECTS-BOUNDS", "INTERSECTS-BOUNDS-10000": + minlat, minlon, maxlat, maxlon := randRect(10000) + redbench.Bench("INTERSECTS (intersects-bounds 10km)", addr, opts, prepFn, + func(buf []byte) []byte { + return redbench.AppendCommand(buf, + "INTERSECTS", "key:bench", "COUNT", "BOUNDS", + strconv.FormatFloat(minlat, 'f', 5, 64), + strconv.FormatFloat(minlon, 'f', 5, 64), + strconv.FormatFloat(maxlat, 'f', 5, 64), + strconv.FormatFloat(maxlon, 'f', 5, 64)) + }, + ) + } + switch strings.ToUpper(strings.TrimSpace(test)) { + case "INTERSECTS", "INTERSECTS-BOUNDS", "INTERSECTS-BOUNDS-100000": + minlat, minlon, maxlat, maxlon := randRect(10000) + redbench.Bench("INTERSECTS (intersects-bounds 100km)", addr, opts, prepFn, + func(buf []byte) []byte { + return redbench.AppendCommand(buf, + "INTERSECTS", "key:bench", "COUNT", "BOUNDS", + strconv.FormatFloat(minlat, 'f', 5, 64), + strconv.FormatFloat(minlon, 'f', 5, 64), + strconv.FormatFloat(maxlat, 'f', 5, 64), + strconv.FormatFloat(maxlon, 'f', 5, 64)) + }, + ) + } + + case "WITHIN", + "WITHIN-RECT", "WITHIN-RECT-1000", "WITHIN-RECT-10000", "WITHIN-RECT-100000", + "WITHIN-CIRCLE", "WITHIN-CIRCLE-1000", "WITHIN-CIRCLE-10000", "WITHIN-CIRCLE-100000": + if redis { + break + } + switch strings.ToUpper(strings.TrimSpace(test)) { + case "WITHIN", "WITHIN-CIRCLE", "WITHIN-CIRCLE-1000": + redbench.Bench("WITHIN (within-circle 1km)", addr, opts, prepFn, + func(buf []byte) []byte { + lat, lon := randPoint() + return redbench.AppendCommand(buf, + "WITHIN", "key:bench", "COUNT", "CIRCLE", + strconv.FormatFloat(lat, 'f', 5, 64), + strconv.FormatFloat(lon, 'f', 5, 64), + "1000") + }, + ) + } + switch strings.ToUpper(strings.TrimSpace(test)) { + case "WITHIN", "WITHIN-CIRCLE", "WITHIN-CIRCLE-10000": + redbench.Bench("WITHIN (within-circle 10km)", addr, opts, prepFn, + func(buf []byte) []byte { + lat, lon := randPoint() + return redbench.AppendCommand(buf, + "WITHIN", "key:bench", "COUNT", "CIRCLE", + strconv.FormatFloat(lat, 'f', 5, 64), + strconv.FormatFloat(lon, 'f', 5, 64), + "10000") + }, + ) + } + switch strings.ToUpper(strings.TrimSpace(test)) { + case "WITHIN", "WITHIN-CIRCLE", "WITHIN-CIRCLE-100000": + redbench.Bench("WITHIN (within-circle 100km)", addr, opts, prepFn, + func(buf []byte) []byte { + lat, lon := randPoint() + return redbench.AppendCommand(buf, + "WITHIN", "key:bench", "COUNT", "CIRCLE", + strconv.FormatFloat(lat, 'f', 5, 64), + strconv.FormatFloat(lon, 'f', 5, 64), + "100000") + }, + ) + } + // WITHIN-BOUNDS + switch strings.ToUpper(strings.TrimSpace(test)) { + case "WITHIN", "WITHIN-BOUNDS", "WITHIN-BOUNDS-1000": + minlat, minlon, maxlat, maxlon := randRect(1000) + redbench.Bench("WITHIN (within-bounds 1km)", addr, opts, prepFn, + func(buf []byte) []byte { + return redbench.AppendCommand(buf, + "WITHIN", "key:bench", "COUNT", "BOUNDS", + strconv.FormatFloat(minlat, 'f', 5, 64), + strconv.FormatFloat(minlon, 'f', 5, 64), + strconv.FormatFloat(maxlat, 'f', 5, 64), + strconv.FormatFloat(maxlon, 'f', 5, 64)) + }, + ) + } + switch strings.ToUpper(strings.TrimSpace(test)) { + case "WITHIN", "WITHIN-BOUNDS", "WITHIN-BOUNDS-10000": + minlat, minlon, maxlat, maxlon := randRect(10000) + redbench.Bench("WITHIN (within-bounds 10km)", addr, opts, prepFn, + func(buf []byte) []byte { + return redbench.AppendCommand(buf, + "WITHIN", "key:bench", "COUNT", "BOUNDS", + strconv.FormatFloat(minlat, 'f', 5, 64), + strconv.FormatFloat(minlon, 'f', 5, 64), + strconv.FormatFloat(maxlat, 'f', 5, 64), + strconv.FormatFloat(maxlon, 'f', 5, 64)) + }, + ) + } + switch strings.ToUpper(strings.TrimSpace(test)) { + case "WITHIN", "WITHIN-BOUNDS", "WITHIN-BOUNDS-100000": + minlat, minlon, maxlat, maxlon := randRect(10000) + redbench.Bench("WITHIN (within-bounds 100km)", addr, opts, prepFn, + func(buf []byte) []byte { + return redbench.AppendCommand(buf, + "WITHIN", "key:bench", "COUNT", "BOUNDS", + strconv.FormatFloat(minlat, 'f', 5, 64), + strconv.FormatFloat(minlon, 'f', 5, 64), + strconv.FormatFloat(maxlat, 'f', 5, 64), + strconv.FormatFloat(maxlon, 'f', 5, 64)) + }, + ) + } + case "NEARBY", + "NEARBY-KNN", "NEARBY-KNN-1", "NEARBY-KNN-10", "NEARBY-KNN-100", + "NEARBY-POINT", "NEARBY-POINT-1000", "NEARBY-POINT-10000", "NEARBY-POINT-100000": + if redis { + break + } + switch strings.ToUpper(strings.TrimSpace(test)) { + case "NEARBY", "NEARBY-KNN", "NEARBY-KNN-1": redbench.Bench("NEARBY (limit 1)", addr, opts, prepFn, func(buf []byte) []byte { lat, lon := randPoint() @@ -316,6 +474,9 @@ func main() { ) }, ) + } + switch strings.ToUpper(strings.TrimSpace(test)) { + case "NEARBY", "NEARBY-KNN", "NEARBY-KNN-10": redbench.Bench("NEARBY (limit 10)", addr, opts, prepFn, func(buf []byte) []byte { lat, lon := randPoint() @@ -326,13 +487,59 @@ func main() { ) }, ) + } + switch strings.ToUpper(strings.TrimSpace(test)) { + case "NEARBY", "NEARBY-KNN", "NEARBY-KNN-100": redbench.Bench("NEARBY (limit 100)", addr, opts, prepFn, func(buf []byte) []byte { lat, lon := randPoint() return redbench.AppendCommand(buf, "NEARBY", "key:bench", "LIMIT", "100", "COUNT", "POINT", strconv.FormatFloat(lat, 'f', 5, 64), - strconv.FormatFloat(lon, 'f', 5, 64)) + strconv.FormatFloat(lon, 'f', 5, 64), + ) + }, + ) + } + switch strings.ToUpper(strings.TrimSpace(test)) { + case "NEARBY", "NEARBY-POINT", "NEARBY-POINT-1000": + redbench.Bench("NEARBY (point 1km)", addr, opts, prepFn, + func(buf []byte) []byte { + lat, lon := randPoint() + return redbench.AppendCommand(buf, + "NEARBY", "key:bench", "COUNT", "POINT", + strconv.FormatFloat(lat, 'f', 5, 64), + strconv.FormatFloat(lon, 'f', 5, 64), + "1000", + ) + }, + ) + } + switch strings.ToUpper(strings.TrimSpace(test)) { + case "NEARBY", "NEARBY-POINT", "NEARBY-POINT-10000": + redbench.Bench("NEARBY (point 10km)", addr, opts, prepFn, + func(buf []byte) []byte { + lat, lon := randPoint() + return redbench.AppendCommand(buf, + "NEARBY", "key:bench", "COUNT", "POINT", + strconv.FormatFloat(lat, 'f', 5, 64), + strconv.FormatFloat(lon, 'f', 5, 64), + "10000", + ) + }, + ) + } + switch strings.ToUpper(strings.TrimSpace(test)) { + case "NEARBY", "NEARBY-POINT", "NEARBY-POINT-100000": + redbench.Bench("NEARBY (point 100km)", addr, opts, prepFn, + func(buf []byte) []byte { + lat, lon := randPoint() + return redbench.AppendCommand(buf, + "NEARBY", "key:bench", "COUNT", "POINT", + strconv.FormatFloat(lat, 'f', 5, 64), + strconv.FormatFloat(lon, 'f', 5, 64), + "100000", + ) }, ) } @@ -407,3 +614,21 @@ func main() { } } } + +const earthRadius = 6371e3 + +func toRadians(deg float64) float64 { return deg * math.Pi / 180 } +func toDegrees(rad float64) float64 { return rad * 180 / math.Pi } + +// destinationPoint return the destination from a point based on a distance and bearing. +func destinationPoint(lat, lon, meters, bearingDegrees float64) (destLat, destLon float64) { + // see http://williams.best.vwh.net/avform.htm#LL + δ := meters / earthRadius // angular distance in radians + θ := toRadians(bearingDegrees) + φ1 := toRadians(lat) + λ1 := toRadians(lon) + φ2 := math.Asin(math.Sin(φ1)*math.Cos(δ) + math.Cos(φ1)*math.Sin(δ)*math.Cos(θ)) + λ2 := λ1 + math.Atan2(math.Sin(θ)*math.Sin(δ)*math.Cos(φ1), math.Cos(δ)-math.Sin(φ1)*math.Sin(φ2)) + λ2 = math.Mod(λ2+3*math.Pi, 2*math.Pi) - math.Pi // normalise to -180..+180° + return toDegrees(φ2), toDegrees(λ2) +} diff --git a/vendor/github.com/tidwall/redbench/bench.go b/vendor/github.com/tidwall/redbench/bench.go index 9f7b4e9e..464f5cad 100644 --- a/vendor/github.com/tidwall/redbench/bench.go +++ b/vendor/github.com/tidwall/redbench/bench.go @@ -14,7 +14,7 @@ import ( "time" ) -func readResp(rd *bufio.Reader, n int) error { +func readResp(rd *bufio.Reader, n int, opts *Options) error { for i := 0; i < n; i++ { line, err := rd.ReadBytes('\n') if err != nil { @@ -25,6 +25,7 @@ func readResp(rd *bufio.Reader, n int) error { return errors.New("invalid server response") case '+', ':': case '-': + opts.Stderr.Write(line) case '$': n, err := strconv.ParseInt(string(line[1:len(line)-2]), 10, 64) if err != nil { @@ -40,7 +41,7 @@ func readResp(rd *bufio.Reader, n int) error { if err != nil { return err } - readResp(rd, int(n)) + readResp(rd, int(n), opts) } } return nil @@ -155,7 +156,7 @@ func Bench( if err != nil { return err } - if err := readResp(rd, n); err != nil { + if err := readResp(rd, n, opts); err != nil { return err } stop := time.Since(start) From 545e9316b03eedda0bbebd448945027dfc277525 Mon Sep 17 00:00:00 2001 From: tidwall Date: Sat, 10 Nov 2018 12:35:25 -0700 Subject: [PATCH 06/16] Fix lua scripts --- cmd/tile38-benchmark/main.go | 135 ++++++++++++++++++----------------- 1 file changed, 69 insertions(+), 66 deletions(-) diff --git a/cmd/tile38-benchmark/main.go b/cmd/tile38-benchmark/main.go index 86550b41..972ac6a0 100644 --- a/cmd/tile38-benchmark/main.go +++ b/cmd/tile38-benchmark/main.go @@ -544,73 +544,76 @@ func main() { ) } case "EVAL": - if !redis { - var i int64 - get_script := "return tile38.call('GET', KEYS[1], ARGV[1], 'point')" - get4_script := - "a = tile38.call('GET', KEYS[1], ARGV[1], 'point');" + - "b = tile38.call('GET', KEYS[1], ARGV[2], 'point');" + - "c = tile38.call('GET', KEYS[1], ARGV[3], 'point');" + - "d = tile38.call('GET', KEYS[1], ARGV[4], 'point');" + - "return d" - - set_script := "return tile38.call('SET', KEYS[1], ARGV[1], 'point', ARGV[2], ARGV[3])" - if !opts.Quiet { - fmt.Println("Scripts to run:") - fmt.Println("GET SCRIPT: " + get_script) - fmt.Println("GET FOUR SCRIPT: " + get4_script) - fmt.Println("SET SCRIPT: " + set_script) - } - - redbench.Bench("EVAL (set point)", addr, opts, prepFn, - func(buf []byte) []byte { - i := atomic.AddInt64(&i, 1) - lat, lon := randPoint() - return redbench.AppendCommand(buf, "EVAL", set_script, "1", - "key:bench", - "id:"+strconv.FormatInt(i, 10), - strconv.FormatFloat(lat, 'f', 5, 64), - strconv.FormatFloat(lon, 'f', 5, 64), - ) - }, - ) - redbench.Bench("EVALNA (set point)", addr, opts, prepFn, - func(buf []byte) []byte { - i := atomic.AddInt64(&i, 1) - lat, lon := randPoint() - return redbench.AppendCommand(buf, "EVALNA", set_script, "1", - "key:bench", - "id:"+strconv.FormatInt(i, 10), - strconv.FormatFloat(lat, 'f', 5, 64), - strconv.FormatFloat(lon, 'f', 5, 64), - ) - }, - ) - redbench.Bench("EVALRO (get point)", addr, opts, prepFn, - func(buf []byte) []byte { - i := atomic.AddInt64(&i, 1) - return redbench.AppendCommand(buf, "EVALRO", get_script, "1", "key:bench", "id:"+strconv.FormatInt(i, 10)) - }, - ) - redbench.Bench("EVALRO (get 4 points)", addr, opts, prepFn, - func(buf []byte) []byte { - i := atomic.AddInt64(&i, 1) - return redbench.AppendCommand(buf, "EVALRO", get4_script, "1", - "key:bench", - "id:"+strconv.FormatInt(i, 10), - "id:"+strconv.FormatInt(i+1, 10), - "id:"+strconv.FormatInt(i+2, 10), - "id:"+strconv.FormatInt(i+3, 10), - ) - }, - ) - redbench.Bench("EVALNA (get point)", addr, opts, prepFn, - func(buf []byte) []byte { - i := atomic.AddInt64(&i, 1) - return redbench.AppendCommand(buf, "EVALNA", get_script, "1", "key:bench", "id:"+strconv.FormatInt(i, 10)) - }, - ) + if redis { + break } + var i int64 + getScript := "return tile38.call('GET', KEYS[1], ARGV[1], 'point')" + get4Script := + "local a = tile38.call('GET', KEYS[1], ARGV[1], 'point');" + + "local b = tile38.call('GET', KEYS[1], ARGV[2], 'point');" + + "local c = tile38.call('GET', KEYS[1], ARGV[3], 'point');" + + "local d = tile38.call('GET', KEYS[1], ARGV[4], 'point');" + + "return d" + + setScript := "return tile38.call('SET', KEYS[1], ARGV[1], 'point', ARGV[2], ARGV[3])" + if !opts.Quiet { + fmt.Println("Scripts to run:") + fmt.Println("GET SCRIPT: " + getScript) + fmt.Println("GET FOUR SCRIPT: " + get4Script) + fmt.Println("SET SCRIPT: " + setScript) + } + redbench.Bench("EVAL (set point)", addr, opts, prepFn, + func(buf []byte) []byte { + i := atomic.AddInt64(&i, 1) + lat, lon := randPoint() + return redbench.AppendCommand(buf, "EVAL", setScript, "1", + "key:bench", + "id:"+strconv.FormatInt(i, 10), + strconv.FormatFloat(lat, 'f', 5, 64), + strconv.FormatFloat(lon, 'f', 5, 64), + ) + }, + ) + redbench.Bench("EVALNA (set point)", addr, opts, prepFn, + func(buf []byte) []byte { + i := atomic.AddInt64(&i, 1) + lat, lon := randPoint() + return redbench.AppendCommand(buf, "EVALNA", setScript, "1", + "key:bench", + "id:"+strconv.FormatInt(i, 10), + strconv.FormatFloat(lat, 'f', 5, 64), + strconv.FormatFloat(lon, 'f', 5, 64), + ) + }, + ) + redbench.Bench("EVALRO (get point)", addr, opts, prepFn, + func(buf []byte) []byte { + i := atomic.AddInt64(&i, 1) + args := []string{"EVALRO", getScript, "1", "key:bench", "id:" + strconv.FormatInt(i, 10)} + return redbench.AppendCommand(buf, args...) + }, + ) + redbench.Bench("EVALRO (get 4 points)", addr, opts, prepFn, + func(buf []byte) []byte { + i := atomic.AddInt64(&i, 1) + args := []string{ + "EVALRO", get4Script, "1", + "key:bench", + "id:" + strconv.FormatInt(i, 10), + "id:" + strconv.FormatInt(i+1, 10), + "id:" + strconv.FormatInt(i+2, 10), + "id:" + strconv.FormatInt(i+3, 10), + } + return redbench.AppendCommand(buf, args...) + }, + ) + redbench.Bench("EVALNA (get point)", addr, opts, prepFn, + func(buf []byte) []byte { + i := atomic.AddInt64(&i, 1) + return redbench.AppendCommand(buf, "EVALNA", getScript, "1", "key:bench", "id:"+strconv.FormatInt(i, 10)) + }, + ) } } } From 3bf91077d905aa49f628cf2fa1f1077475b07e08 Mon Sep 17 00:00:00 2001 From: tidwall Date: Sat, 10 Nov 2018 13:30:56 -0700 Subject: [PATCH 07/16] Hang on to lower command --- internal/server/server.go | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/internal/server/server.go b/internal/server/server.go index 546209e6..0b4b30f0 100644 --- a/internal/server/server.go +++ b/internal/server/server.go @@ -656,7 +656,7 @@ func (server *Server) netServe() error { server.flushAOF() }() conn.Write(client.out) - client.out = client.out[:0] + client.out = nil } if close { break @@ -853,6 +853,7 @@ func (server *Server) handleInputCommand(client *Client, msg *Message) error { return err } } + // Ping. Just send back the response. No need to put through the pipeline. if msg.Command() == "ping" || msg.Command() == "echo" { switch msg.OutputType { @@ -870,6 +871,7 @@ func (server *Server) handleInputCommand(client *Client, msg *Message) error { } return nil } + writeErr := func(errMsg string) error { switch msg.OutputType { case JSON: @@ -913,6 +915,7 @@ func (server *Server) handleInputCommand(client *Client, msg *Message) error { return writeErr("invalid password") } } + // choose the locking strategy switch msg.Command() { default: @@ -946,6 +949,7 @@ func (server *Server) handleInputCommand(client *Client, msg *Message) error { "chans", "search", "ttl", "bounds", "server", "info", "type", "jget", "evalro", "evalrosha": // read operations + server.mu.RLock() defer server.mu.RUnlock() if server.config.followHost() != "" && !server.fcuponce { @@ -984,7 +988,6 @@ func (server *Server) handleInputCommand(client *Client, msg *Message) error { } res, d, err := server.command(msg, client) - if res.Type() == resp.Error { return writeErr(res.String()) } @@ -1003,7 +1006,6 @@ func (server *Server) handleInputCommand(client *Client, msg *Message) error { return err } } - if !isRespValueEmptyString(res) { var resStr string resStr, err := serializeOutput(res) @@ -1275,6 +1277,7 @@ const ( // Message is a resp message type Message struct { + _command string Args []string ConnType Type OutputType Type @@ -1283,7 +1286,10 @@ type Message struct { // Command returns the first argument as a lowercase string func (msg *Message) Command() string { - return strings.ToLower(msg.Args[0]) + if msg._command == "" { + msg._command = strings.ToLower(msg.Args[0]) + } + return msg._command } // PipelineReader ... From 464c193d73f55887707cf254d43c3b5bca4faec8 Mon Sep 17 00:00:00 2001 From: tidwall Date: Sat, 10 Nov 2018 16:16:04 -0700 Subject: [PATCH 08/16] Prewrite optimization flag --- internal/server/aof.go | 2 ++ internal/server/server.go | 26 +++++++++++++++----------- 2 files changed, 17 insertions(+), 11 deletions(-) diff --git a/internal/server/aof.go b/internal/server/aof.go index ef127b0c..3d038347 100644 --- a/internal/server/aof.go +++ b/internal/server/aof.go @@ -9,6 +9,7 @@ import ( "strconv" "strings" "sync" + "sync/atomic" "time" "github.com/tidwall/buntdb" @@ -152,6 +153,7 @@ func (server *Server) writeAOF(args []string, d *commandDetailsT) error { } if server.aof != nil { + atomic.StoreInt32(&server.aofdirty, 1) // prewrite optimization flag n := len(server.aofbuf) server.aofbuf = redcon.AppendArray(server.aofbuf, len(args)) for _, arg := range args { diff --git a/internal/server/server.go b/internal/server/server.go index 0b4b30f0..9a21b438 100644 --- a/internal/server/server.go +++ b/internal/server/server.go @@ -92,14 +92,15 @@ type Server struct { exlistmu sync.RWMutex exlist []exitem - mu sync.RWMutex - aof *os.File // active aof file - aofbuf []byte // prewrite buffer - aofsz int // active size of the aof file - qdb *buntdb.DB // hook queue log - qidx uint64 // hook queue log last idx - cols ds.BTree // data collections - expires map[string]map[string]time.Time // synced with cols + mu sync.RWMutex + aof *os.File // active aof file + aofdirty int32 // mark the aofbuf as having data + aofbuf []byte // prewrite buffer + aofsz int // active size of the aof file + qdb *buntdb.DB // hook queue log + qidx uint64 // hook queue log last idx + cols ds.BTree // data collections + expires map[string]map[string]time.Time // synced with cols follows map[*bytes.Buffer]bool fcond *sync.Cond @@ -476,9 +477,12 @@ func (server *Server) evioServe() error { } events.PreWrite = func() { - server.mu.Lock() - defer server.mu.Unlock() - server.flushAOF() + if atomic.LoadInt32(&server.aofdirty) != 0 { + server.mu.Lock() + defer server.mu.Unlock() + server.flushAOF() + atomic.StoreInt32(&server.aofdirty, 1) + } } return evio.Serve(events, fmt.Sprintf("%s:%d", server.host, server.port)) From d065b979dae3b2474f413eecff551313c37c5a7d Mon Sep 17 00:00:00 2001 From: tidwall Date: Sat, 10 Nov 2018 16:21:07 -0700 Subject: [PATCH 09/16] net prewrite optimization --- internal/server/server.go | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/internal/server/server.go b/internal/server/server.go index 9a21b438..3ed61699 100644 --- a/internal/server/server.go +++ b/internal/server/server.go @@ -653,14 +653,18 @@ func (server *Server) netServe() error { // write to client if len(client.out) > 0 { - func() { - // prewrite - server.mu.Lock() - defer server.mu.Unlock() - server.flushAOF() - }() + if atomic.LoadInt32(&server.aofdirty) != 0 { + func() { + // prewrite + server.mu.Lock() + defer server.mu.Unlock() + server.flushAOF() + }() + atomic.StoreInt32(&server.aofdirty, 0) + } conn.Write(client.out) client.out = nil + } if close { break From 7cc9154eb8b173adcf1a7c5fa0d0192150bd36a1 Mon Sep 17 00:00:00 2001 From: tidwall Date: Sat, 10 Nov 2018 17:14:34 -0700 Subject: [PATCH 10/16] Correct threads equals cpu --- internal/server/server.go | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/internal/server/server.go b/internal/server/server.go index 3ed61699..520116c5 100644 --- a/internal/server/server.go +++ b/internal/server/server.go @@ -22,6 +22,7 @@ import ( "sync/atomic" "time" + "github.com/klauspost/cpuid" "github.com/tidwall/buntdb" "github.com/tidwall/evio" "github.com/tidwall/geojson" @@ -294,7 +295,12 @@ func (server *Server) isProtected() bool { func (server *Server) evioServe() error { var events evio.Events if core.NumThreads == 0 { - events.NumLoops = -1 + cores := cpuid.CPU.PhysicalCores + if cores == 0 { + events.NumLoops = -1 + } else { + events.NumLoops = cores + } } else { events.NumLoops = core.NumThreads } From a160fa0860b114297f252103afa70c65e5497ac8 Mon Sep 17 00:00:00 2001 From: tidwall Date: Sat, 10 Nov 2018 20:30:35 -0700 Subject: [PATCH 11/16] wip: cricle --- vendor/github.com/tidwall/geojson/circle.go | 92 ++++++++++++++++++++- 1 file changed, 88 insertions(+), 4 deletions(-) diff --git a/vendor/github.com/tidwall/geojson/circle.go b/vendor/github.com/tidwall/geojson/circle.go index 3cdd8492..50bac786 100644 --- a/vendor/github.com/tidwall/geojson/circle.go +++ b/vendor/github.com/tidwall/geojson/circle.go @@ -1,7 +1,9 @@ package geojson import ( + "math" "strconv" + "sync" "github.com/tidwall/geojson/geo" "github.com/tidwall/geojson/geometry" @@ -210,12 +212,46 @@ func (g *Circle) getObject() Object { return makeCircleObject(g.center, g.meters, g.steps) } -func makeCircleObject(center geometry.Point, meters float64, steps int) Object { +var llmu sync.RWMutex +var llobj Object + +func makeCircleObjectA(center geometry.Point, meters float64, steps int) Object { if meters <= 0 { return NewPoint(center) } meters = geo.NormalizeDistance(meters) - var points []geometry.Point + points := make([]geometry.Point, 0, steps+1) + + // calc the four corners + maxY, _ := geo.DestinationPoint(center.Y, center.X, meters, 0) + _, maxX := geo.DestinationPoint(center.Y, center.X, meters, 90) + minY, _ := geo.DestinationPoint(center.Y, center.X, meters, 180) + _, minX := geo.DestinationPoint(center.Y, center.X, meters, 270) + lons := (maxX - minX) / 2 + lats := (maxY - minY) / 2 + + for th := 0.0; th <= 360.0; th += 360.0 / float64(steps) { + radians := (math.Pi / 180) * th + x := center.X + lats*math.Cos(radians) + y := center.Y + lons*math.Sin(radians) + points = append(points, geometry.Point{X: x, Y: y}) + } + // add last connecting point, make a total of steps+1 + points = append(points, points[0]) + + return NewPolygon( + geometry.NewPoly(points, nil, &geometry.IndexOptions{ + Kind: geometry.None, + }), + ) +} +func makeCircleObjectB(center geometry.Point, meters float64, steps int) Object { + if meters <= 0 { + return NewPoint(center) + } + meters = geo.NormalizeDistance(meters) + points := make([]geometry.Point, 0, steps+1) + step := 360.0 / float64(steps) i := 0 for deg := 360.0; deg > 0; deg -= step { @@ -223,11 +259,59 @@ func makeCircleObject(center geometry.Point, meters float64, steps int) Object { points = append(points, geometry.Point{X: lon, Y: lat}) i++ } + // add last connecting point, make a total of steps+1 + points = append(points, points[0]) + + return NewPolygon( + geometry.NewPoly(points, nil, &geometry.IndexOptions{ + Kind: geometry.None, + }), + ) +} + +func makeCircleObject(center geometry.Point, meters float64, steps int) Object { + if meters <= 0 { + return NewPoint(center) + } + + meters = geo.NormalizeDistance(meters) + points := make([]geometry.Point, 0, steps+1) + return makeCircleObjectA(center, meters, steps) + + llmu.RLock() + if llobj != nil { + llmu.RUnlock() + return llobj + } + llmu.RUnlock() + llmu.Lock() + if llobj != nil { + llmu.Unlock() + return llobj + } + defer llmu.Unlock() + + step := 360.0 / float64(steps) + i := 0 + for deg := 360.0; deg > 0; deg -= step { + lat, lon := geo.DestinationPoint(center.Y, center.X, meters, deg) + points = append(points, geometry.Point{X: lon, Y: lat}) + i++ + } + // add last connecting point, make a total of steps+1 + points = append(points, points[0]) + + // for i := 0; i < steps; i++ { + // fmt.Printf("%d: %v\n", i, points[i].X) + // } + // TODO: account for the pole and antimerdian. In most cases only a // polygon is needed, but when the circle bounds passes the 90/180 // lines, we need to create a multipolygon - points = append(points, points[0]) - return NewPolygon( + + llobj = NewPolygon( geometry.NewPoly(points, nil, geometry.DefaultIndexOptions), ) + // println(llobj.String()) + return llobj } From b2203fcb975a96dd59a4dc231edc7a4383852b7c Mon Sep 17 00:00:00 2001 From: tidwall Date: Sun, 11 Nov 2018 06:26:23 -0700 Subject: [PATCH 12/16] Fix nearby fast-fail --- internal/collection/collection.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/internal/collection/collection.go b/internal/collection/collection.go index ed8555ce..d8fe0515 100644 --- a/internal/collection/collection.go +++ b/internal/collection/collection.go @@ -674,9 +674,9 @@ func (c *Collection) Nearby( cursor Cursor, iter func(id string, obj geojson.Object, fields []float64) bool, ) bool { - + // First look to see if there's at least one candidate in the circle's + // outer rectangle. This is a fast-fail operation. if circle, ok := target.(*geojson.Circle); ok { - meters := circle.Meters() if meters > 0 { center := circle.Center() @@ -692,12 +692,12 @@ func (c *Collection) Nearby( }, ) if !exists { + // no candidates return true } - return true } } - + // do the kNN operation alive := true center := target.Center() var count uint64 From 090a05735f0c491243a5c82288e5cf8ef649ad34 Mon Sep 17 00:00:00 2001 From: tidwall Date: Sun, 11 Nov 2018 07:35:31 -0700 Subject: [PATCH 13/16] Added az benchmark test --- cmd/tile38-benchmark/az/az.go | 6 ++ cmd/tile38-benchmark/main.go | 186 +++++++++++++++++++++------------- 2 files changed, 122 insertions(+), 70 deletions(-) create mode 100644 cmd/tile38-benchmark/az/az.go diff --git a/cmd/tile38-benchmark/az/az.go b/cmd/tile38-benchmark/az/az.go new file mode 100644 index 00000000..536b1362 --- /dev/null +++ b/cmd/tile38-benchmark/az/az.go @@ -0,0 +1,6 @@ +package az + +// JSON is GeoJSON +var JSON = ` +{ "type": "MultiPolygon", "coordinates": [ [ [ [ -114.635458, 34.876902 ], [ -114.636768000000103, 34.885705 ], [ -114.636725, 34.889107 ], [ -114.635425, 34.895192 ], [ -114.63185, 34.903942 ], [ -114.630877, 34.907263 ], [ -114.630552, 34.911852 ], [ -114.631537, 34.916153 ], [ -114.633237, 34.92123 ], [ -114.633253, 34.924608 ], [ -114.632196, 34.930628 ], [ -114.629753, 34.938684 ], [ -114.629811, 34.94481 ], [ -114.631681, 34.95131 ], [ -114.634274, 34.956662 ], [ -114.634953, 34.958918 ], [ -114.635237000000103, 34.965149 ], [ -114.634607, 34.96906 ], [ -114.629907, 34.980791 ], [ -114.629129, 34.986132 ], [ -114.629443, 34.991825 ], [ -114.630244000000104, 34.99464 ], [ -114.631807, 34.998632 ], [ -114.632665, 34.999806 ], [ -114.635570000000101, 35.005933 ], [ -114.637071, 35.010371 ], [ -114.637769, 35.014948 ], [ -114.63819, 35.022069 ], [ -114.637524, 35.027053 ], [ -114.633715, 35.035602 ], [ -114.629027, 35.042531 ], [ -114.625799, 35.045834 ], [ -114.615902, 35.05272 ], [ -114.610701000000105, 35.055458 ], [ -114.606694, 35.058941 ], [ -114.604715, 35.061744 ], [ -114.603619, 35.064226 ], [ -114.602908, 35.068588 ], [ -114.603175, 35.070445 ], [ -114.604736, 35.07483 ], [ -114.607701, 35.078533 ], [ -114.613132, 35.083097 ], [ -114.61842, 35.086539 ], [ -114.622517, 35.088703 ], [ -114.632053, 35.092559 ], [ -114.63937, 35.094733 ], [ -114.642831, 35.096503 ], [ -114.646579, 35.10082 ], [ -114.646764, 35.101868 ], [ -114.645152, 35.104995 ], [ -114.644354, 35.105903 ], [ -114.641116, 35.108401 ], [ -114.637432000000103, 35.112489 ], [ -114.632282, 35.117088 ], [ -114.628427, 35.118943 ], [ -114.623761, 35.120602 ], [ -114.628993, 35.119411 ], [ -114.624954000000102, 35.120742 ], [ -114.618697, 35.121749 ], [ -114.604007, 35.121252 ], [ -114.60274, 35.121666 ], [ -114.597794, 35.121735 ], [ -114.589787, 35.123522 ], [ -114.584877, 35.125194 ], [ -114.579882, 35.127506 ], [ -114.578263, 35.12881 ], [ -114.577146, 35.130982 ], [ -114.574411, 35.13495 ], [ -114.572597, 35.139557 ], [ -114.573706, 35.142698 ], [ -114.573879, 35.145351 ], [ -114.569529, 35.162317 ], [ -114.56876, 35.172195 ], [ -114.569214, 35.17289 ], [ -114.568989, 35.175085 ], [ -114.569258, 35.183424 ], [ -114.569653, 35.186267 ], [ -114.571404, 35.191026 ], [ -114.572084, 35.200794 ], [ -114.574037, 35.20379 ], [ -114.574233, 35.205481 ], [ -114.574958, 35.206714 ], [ -114.578581, 35.208113 ], [ -114.579535, 35.208911 ], [ -114.579897000000102, 35.21097 ], [ -114.580312, 35.220095 ], [ -114.583523, 35.230348 ], [ -114.58248, 35.233173 ], [ -114.582842, 35.238703 ], [ -114.584993, 35.242717 ], [ -114.586053, 35.248891 ], [ -114.585714, 35.253145 ], [ -114.585768, 35.257743 ], [ -114.586604, 35.262386 ], [ -114.587497, 35.265473 ], [ -114.590513, 35.272334 ], [ -114.593247, 35.284361 ], [ -114.595705, 35.289939 ], [ -114.596682, 35.294557 ], [ -114.597268, 35.299565 ], [ -114.59721, 35.303223 ], [ -114.595163, 35.321883 ], [ -114.595553, 35.326547 ], [ -114.599771, 35.34111 ], [ -114.604607, 35.355239 ], [ -114.606173, 35.359651 ], [ -114.611206, 35.370119 ], [ -114.617698, 35.380131 ], [ -114.618257, 35.382646 ], [ -114.618984, 35.389391 ], [ -114.620887, 35.396867 ], [ -114.621783, 35.39945 ], [ -114.625702, 35.407976 ], [ -114.626765, 35.409644 ], [ -114.629061000000107, 35.411175 ], [ -114.65208, 35.430134 ], [ -114.653817, 35.432853 ], [ -114.654295, 35.436854 ], [ -114.658105, 35.441835 ], [ -114.661747, 35.444735 ], [ -114.662896, 35.446449 ], [ -114.663934, 35.449466 ], [ -114.664215, 35.451707 ], [ -114.663880000000105, 35.454657 ], [ -114.664217, 35.455845 ], [ -114.665142, 35.457331 ], [ -114.666151, 35.458198 ], [ -114.667217, 35.46037 ], [ -114.666769000000102, 35.462085 ], [ -114.665790000000101, 35.463915 ], [ -114.665651, 35.466911 ], [ -114.665988, 35.467985 ], [ -114.667389, 35.469904 ], [ -114.67235, 35.47374 ], [ -114.673164, 35.474814 ], [ -114.673585, 35.475843 ], [ -114.673473000000101, 35.476849 ], [ -114.672074, 35.479709 ], [ -114.671794, 35.480806 ], [ -114.671907, 35.482087 ], [ -114.673534, 35.485675 ], [ -114.676815000000104, 35.489787 ], [ -114.6767040000001, 35.491845 ], [ -114.676257, 35.493103 ], [ -114.677743, 35.495182 ], [ -114.678642, 35.497628 ], [ -114.678587, 35.499846 ], [ -114.678892000000104, 35.501276 ], [ -114.67748, 35.510948 ], [ -114.677143, 35.512945 ], [ -114.675685, 35.51563 ], [ -114.672767, 35.518428 ], [ -114.66954, 35.52079 ], [ -114.668586, 35.521225 ], [ -114.666565, 35.520993 ], [ -114.664601000000104, 35.521519 ], [ -114.663983000000101, 35.522161 ], [ -114.661682, 35.526682 ], [ -114.659886, 35.527919 ], [ -114.657753, 35.530741 ], [ -114.657163, 35.532301 ], [ -114.65677, 35.534964 ], [ -114.657809, 35.536963 ], [ -114.660335, 35.540433 ], [ -114.661457, 35.544062 ], [ -114.66157, 35.545692 ], [ -114.66112, 35.549021 ], [ -114.661963, 35.552604 ], [ -114.661963, 35.555887 ], [ -114.663451, 35.559884 ], [ -114.663535, 35.560963 ], [ -114.662805, 35.564268 ], [ -114.6639, 35.56629 ], [ -114.664433000000102, 35.568426 ], [ -114.666231, 35.571642 ], [ -114.668393, 35.574331 ], [ -114.670022, 35.575596 ], [ -114.671567, 35.576217 ], [ -114.674881, 35.578379 ], [ -114.675751, 35.579459 ], [ -114.675667, 35.580033 ], [ -114.670191, 35.583471 ], [ -114.664209, 35.585944 ], [ -114.660558, 35.586583 ], [ -114.659238, 35.587477 ], [ -114.654518, 35.596609 ], [ -114.653900000000107, 35.598491 ], [ -114.653731, 35.600373 ], [ -114.654489, 35.605173 ], [ -114.653618, 35.607192 ], [ -114.653534, 35.609672 ], [ -114.653927, 35.611739 ], [ -114.655219, 35.614059 ], [ -114.657241, 35.617046 ], [ -114.659461, 35.619552 ], [ -114.660641, 35.620334 ], [ -114.663647, 35.620773 ], [ -114.665389, 35.621556 ], [ -114.666682, 35.623073 ], [ -114.668087, 35.627115 ], [ -114.669015000000101, 35.628861 ], [ -114.672134, 35.633365 ], [ -114.675001, 35.638304 ], [ -114.677615, 35.641774 ], [ -114.679415000000105, 35.643429 ], [ -114.686133, 35.647522 ], [ -114.689001, 35.65028 ], [ -114.689507, 35.651429 ], [ -114.689226, 35.652898 ], [ -114.690494000000101, 35.662657 ], [ -114.690214, 35.665159 ], [ -114.686055, 35.670642 ], [ -114.682317, 35.677825 ], [ -114.680827, 35.682255 ], [ -114.680631000000105, 35.684046 ], [ -114.680997000000104, 35.685929 ], [ -114.682657000000106, 35.688571 ], [ -114.691263, 35.693125 ], [ -114.696214, 35.69655 ], [ -114.701416, 35.701084 ], [ -114.703608, 35.703922 ], [ -114.704501, 35.705993 ], [ -114.704959, 35.706366 ], [ -114.704842, 35.706744 ], [ -114.705597, 35.708274 ], [ -114.705347000000103, 35.708344 ], [ -114.705447, 35.711757 ], [ -114.699405, 35.726929 ], [ -114.697859, 35.731657 ], [ -114.69654, 35.738934 ], [ -114.6964, 35.742653 ], [ -114.696655, 35.746143 ], [ -114.697585, 35.748417 ], [ -114.697726, 35.750966 ], [ -114.696854, 35.752756 ], [ -114.696546, 35.754638 ], [ -114.694267, 35.756633 ], [ -114.694717, 35.757897 ], [ -114.69742, 35.760677 ], [ -114.700266, 35.766879 ], [ -114.701027, 35.76968 ], [ -114.70117, 35.774112 ], [ -114.699036000000106, 35.788046 ], [ -114.699318000000105, 35.79048 ], [ -114.703178, 35.794685 ], [ -114.705827, 35.798889 ], [ -114.71149, 35.80438 ], [ -114.712026, 35.805529 ], [ -114.710534, 35.807525 ], [ -114.709324, 35.81005 ], [ -114.70634, 35.812022 ], [ -114.703665, 35.814614 ], [ -114.700654, 35.822004 ], [ -114.697276, 35.826776 ], [ -114.69553, 35.829897 ], [ -114.695277000000104, 35.831091 ], [ -114.695249, 35.832285 ], [ -114.695757, 35.833387 ], [ -114.701478, 35.839316 ], [ -114.702293, 35.840792 ], [ -114.702339, 35.842151 ], [ -114.703527, 35.841845 ], [ -114.704173, 35.842669 ], [ -114.704203000000106, 35.844274 ], [ -114.706288, 35.846218 ], [ -114.706532, 35.849027 ], [ -114.705856, 35.850508 ], [ -114.703599, 35.852595 ], [ -114.701904, 35.853223 ], [ -114.696581, 35.853727 ], [ -114.69437, 35.854463 ], [ -114.693446, 35.855125 ], [ -114.691456, 35.858661 ], [ -114.6877980000001, 35.860728 ], [ -114.68205, 35.86295 ], [ -114.678186, 35.863311 ], [ -114.672289, 35.865011 ], [ -114.66968, 35.865036 ], [ -114.667471000000106, 35.867061 ], [ -114.662623, 35.869213 ], [ -114.661636, 35.870545 ], [ -114.661636, 35.871233 ], [ -114.663214, 35.873692 ], [ -114.668145, 35.875201 ], [ -114.672009, 35.878018 ], [ -114.678972, 35.88551 ], [ -114.693602, 35.895311 ], [ -114.69454, 35.896587 ], [ -114.696064, 35.896464 ], [ -114.694928, 35.897594 ], [ -114.696132000000105, 35.898662 ], [ -114.697558, 35.89936 ], [ -114.700258000000105, 35.901757 ], [ -114.700769, 35.903064 ], [ -114.703538, 35.906707 ], [ -114.705119, 35.907637 ], [ -114.705991, 35.908598 ], [ -114.7057140000001, 35.909316 ], [ -114.706767, 35.90895 ], [ -114.708112, 35.909933 ], [ -114.709187, 35.916827 ], [ -114.707784, 35.916993 ], [ -114.707398, 35.918057 ], [ -114.70788, 35.919207 ], [ -114.707329000000101, 35.926177 ], [ -114.707603, 35.92795 ], [ -114.712965, 35.932159 ], [ -114.712756, 35.932639 ], [ -114.713413, 35.9319 ], [ -114.713312, 35.933844 ], [ -114.729762, 35.959895 ], [ -114.728496000000106, 35.960395 ], [ -114.728666, 35.961757 ], [ -114.730090000000104, 35.962691 ], [ -114.732456, 35.965891 ], [ -114.736195, 35.969421 ], [ -114.740536, 35.975545 ], [ -114.743494, 35.983553 ], [ -114.743638, 35.985785 ], [ -114.743117, 35.987387 ], [ -114.740043, 35.990534 ], [ -114.739318, 35.991804 ], [ -114.740544, 35.994853 ], [ -114.740815, 35.997464 ], [ -114.741536, 35.99969 ], [ -114.741679, 36.002283 ], [ -114.743163, 36.006722 ], [ -114.743005, 36.00845 ], [ -114.740866, 36.012928 ], [ -114.738555, 36.015223 ], [ -114.728874000000104, 36.021387 ], [ -114.723324, 36.026588 ], [ -114.722214, 36.027964 ], [ -114.722096, 36.028952 ], [ -114.722742, 36.030286 ], [ -114.723673, 36.03123 ], [ -114.727602, 36.033099 ], [ -114.730563, 36.036207 ], [ -114.733417000000102, 36.037913 ], [ -114.735739, 36.038033 ], [ -114.740018, 36.037467 ], [ -114.741262000000106, 36.038044 ], [ -114.742105, 36.039792 ], [ -114.742661, 36.042573 ], [ -114.742479, 36.045697 ], [ -114.741677, 36.047877 ], [ -114.735701, 36.053393 ], [ -114.73508, 36.054435 ], [ -114.735285, 36.056648 ], [ -114.736023000000102, 36.059063 ], [ -114.74006, 36.062437 ], [ -114.7422, 36.067833 ], [ -114.742138, 36.068676 ], [ -114.743542, 36.071037 ], [ -114.748891, 36.074981 ], [ -114.75057, 36.08033 ], [ -114.754032, 36.083093 ], [ -114.754681, 36.085052 ], [ -114.754508, 36.086171 ], [ -114.752836, 36.089393 ], [ -114.750095, 36.092275 ], [ -114.748913000000101, 36.095183 ], [ -114.737497000000104, 36.103102 ], [ -114.734857, 36.104426 ], [ -114.718257, 36.107164 ], [ -114.709269, 36.107396 ], [ -114.706091, 36.108239 ], [ -114.703737, 36.108348 ], [ -114.696981, 36.110297 ], [ -114.693655000000106, 36.112482 ], [ -114.691631, 36.112535 ], [ -114.6880740000001, 36.111457 ], [ -114.684426000000101, 36.109472 ], [ -114.681847000000104, 36.109192 ], [ -114.679775000000106, 36.109874 ], [ -114.678375, 36.110815 ], [ -114.675106, 36.114111 ], [ -114.671867, 36.115964 ], [ -114.664343000000102, 36.1163 ], [ -114.662144, 36.117742 ], [ -114.660448, 36.119999 ], [ -114.658131, 36.124127 ], [ -114.655512, 36.126187 ], [ -114.645728, 36.131995 ], [ -114.641976, 36.13373 ], [ -114.640125, 36.135126 ], [ -114.636862, 36.135552 ], [ -114.635809, 36.13617 ], [ -114.630474, 36.142218 ], [ -114.628462, 36.141822 ], [ -114.627079, 36.140761 ], [ -114.623837, 36.137144 ], [ -114.620605, 36.131759 ], [ -114.618429, 36.130328 ], [ -114.615455, 36.129653 ], [ -114.61324, 36.130266 ], [ -114.609288, 36.132229 ], [ -114.596474, 36.141537 ], [ -114.5930350000001, 36.142674 ], [ -114.589828, 36.143192 ], [ -114.583716, 36.14556 ], [ -114.580707, 36.145987 ], [ -114.578828, 36.147175 ], [ -114.57706, 36.148845 ], [ -114.57109, 36.151099 ], [ -114.561173, 36.150921 ], [ -114.556162, 36.15247 ], [ -114.548742000000104, 36.150697 ], [ -114.543232, 36.151871 ], [ -114.539233, 36.151764 ], [ -114.534478, 36.15023 ], [ -114.532924, 36.149282 ], [ -114.532308, 36.14804 ], [ -114.531091, 36.147644 ], [ -114.52621, 36.148177 ], [ -114.51428, 36.150795 ], [ -114.511218, 36.150576 ], [ -114.508104000000102, 36.149713 ], [ -114.501049, 36.144516 ], [ -114.500236, 36.143226 ], [ -114.499992, 36.141594 ], [ -114.500339, 36.1407 ], [ -114.50108, 36.14006 ], [ -114.50515, 36.138078 ], [ -114.507175, 36.13634 ], [ -114.50921, 36.133247 ], [ -114.508467, 36.129913 ], [ -114.507201, 36.128484 ], [ -114.504715, 36.127188 ], [ -114.501798, 36.126556 ], [ -114.498849, 36.126612 ], [ -114.487635, 36.128656 ], [ -114.483827, 36.12972 ], [ -114.478248, 36.132683 ], [ -114.468674, 36.138889 ], [ -114.465579, 36.139496 ], [ -114.4626, 36.139644 ], [ -114.458945, 36.139214 ], [ -114.456487, 36.138032 ], [ -114.45511, 36.136372 ], [ -114.453798, 36.133586 ], [ -114.451331, 36.129831 ], [ -114.447135, 36.126022 ], [ -114.445042, 36.125346 ], [ -114.443736, 36.125593 ], [ -114.435507, 36.130057 ], [ -114.423114, 36.13735 ], [ -114.418193, 36.142771 ], [ -114.415253, 36.145123 ], [ -114.412491000000102, 36.146511 ], [ -114.40914, 36.147 ], [ -114.405624, 36.146983 ], [ -114.398373, 36.145799 ], [ -114.381479, 36.141349 ], [ -114.379976, 36.141388 ], [ -114.375278, 36.143592 ], [ -114.373745, 36.143722 ], [ -114.370181, 36.142624 ], [ -114.368551, 36.140892 ], [ -114.367381, 36.13852 ], [ -114.365529, 36.136306 ], [ -114.364499, 36.134072 ], [ -114.358968, 36.127795 ], [ -114.348592, 36.121147 ], [ -114.3451, 36.118556 ], [ -114.342601, 36.115878 ], [ -114.34095, 36.113457 ], [ -114.338815, 36.111309 ], [ -114.337264, 36.110428 ], [ -114.334632, 36.106784 ], [ -114.333587, 36.106342 ], [ -114.328801, 36.105902 ], [ -114.325814, 36.103933 ], [ -114.325539, 36.102989 ], [ -114.323458000000102, 36.101186 ], [ -114.320866, 36.096463 ], [ -114.316983, 36.093409 ], [ -114.313086, 36.088816 ], [ -114.306939, 36.082487 ], [ -114.304171, 36.07558 ], [ -114.304384, 36.074019 ], [ -114.305853, 36.071478 ], [ -114.307485, 36.069672 ], [ -114.31242, 36.066117 ], [ -114.3136, 36.064148 ], [ -114.314328, 36.062016 ], [ -114.314427, 36.060523 ], [ -114.313591, 36.059048 ], [ -114.311904, 36.057661 ], [ -114.308624, 36.056976 ], [ -114.300971000000104, 36.05746 ], [ -114.298593, 36.057263 ], [ -114.295941, 36.056168 ], [ -114.293435000000102, 36.0545 ], [ -114.290867, 36.050511 ], [ -114.287992, 36.04907 ], [ -114.284006, 36.048242 ], [ -114.279637, 36.046103 ], [ -114.278166, 36.045819 ], [ -114.273911, 36.046529 ], [ -114.272299, 36.046289 ], [ -114.270862, 36.045523 ], [ -114.269548, 36.043769 ], [ -114.268896, 36.04094 ], [ -114.26922, 36.036807 ], [ -114.268586, 36.035034 ], [ -114.26438, 36.027911 ], [ -114.262388, 36.026107 ], [ -114.259518, 36.024206 ], [ -114.251633, 36.019886 ], [ -114.248419, 36.018556 ], [ -114.246111, 36.017164 ], [ -114.243865, 36.015266 ], [ -114.240439, 36.015245 ], [ -114.238154, 36.014473 ], [ -114.236892, 36.013247 ], [ -114.233443, 36.012835 ], [ -114.231854, 36.013147 ], [ -114.228015, 36.014731 ], [ -114.226459, 36.014606 ], [ -114.224798, 36.013699 ], [ -114.218759, 36.014511 ], [ -114.216609, 36.014336 ], [ -114.214679, 36.014806 ], [ -114.213549, 36.014615 ], [ -114.211932, 36.014834 ], [ -114.206052, 36.016634 ], [ -114.204156, 36.016575 ], [ -114.201227, 36.017751 ], [ -114.200066, 36.017743 ], [ -114.191221, 36.020019 ], [ -114.185860000000105, 36.022266 ], [ -114.179438, 36.024313 ], [ -114.176304, 36.026129 ], [ -114.174683, 36.02667 ], [ -114.164402, 36.026852 ], [ -114.161237, 36.026279 ], [ -114.157344, 36.024966 ], [ -114.1534, 36.02317 ], [ -114.15139, 36.023133 ], [ -114.150225, 36.023515 ], [ -114.145907, 36.027229 ], [ -114.145637, 36.028559 ], [ -114.145672, 36.03297 ], [ -114.144666, 36.034272 ], [ -114.143153, 36.035295 ], [ -114.13826, 36.03719 ], [ -114.137112, 36.038491 ], [ -114.135721, 36.041238 ], [ -114.134841, 36.043873 ], [ -114.134824, 36.045343 ], [ -114.135927, 36.050358 ], [ -114.136206, 36.053232 ], [ -114.1352, 36.056946 ], [ -114.133389, 36.061665 ], [ -114.129768, 36.068484 ], [ -114.125891, 36.072935 ], [ -114.124019, 36.075563 ], [ -114.121186, 36.082755 ], [ -114.119648, 36.085822 ], [ -114.112297, 36.09405 ], [ -114.111998, 36.09491 ], [ -114.1119, 36.095845 ], [ -114.115208, 36.099878 ], [ -114.11707, 36.101177 ], [ -114.119329, 36.10193 ], [ -114.121033, 36.103885 ], [ -114.121779, 36.105699 ], [ -114.12167, 36.108294 ], [ -114.120865, 36.11085 ], [ -114.118497, 36.1139 ], [ -114.116061, 36.115471 ], [ -114.108381, 36.119154 ], [ -114.107419, 36.119401 ], [ -114.100433, 36.119359 ], [ -114.097707, 36.120213 ], [ -114.096994, 36.120823 ], [ -114.092753, 36.132356 ], [ -114.092366, 36.135331 ], [ -114.091701, 36.137303 ], [ -114.089279, 36.140326 ], [ -114.087899, 36.142923 ], [ -114.081234, 36.150208 ], [ -114.07945, 36.154625 ], [ -114.078832, 36.157434 ], [ -114.075641, 36.162523 ], [ -114.071652, 36.170921 ], [ -114.066798, 36.179087 ], [ -114.058662, 36.187835 ], [ -114.052743, 36.190919 ], [ -114.049484, 36.192134 ], [ -114.043944, 36.19335 ], [ -114.043849, 36.245114 ], [ -114.045518, 36.27439 ], [ -114.045559, 36.288837 ], [ -114.045033, 36.30305 ], [ -114.044345, 36.310234 ], [ -114.044051, 36.317628 ], [ -114.044776, 36.331969 ], [ -114.044702, 36.346298 ], [ -114.043034, 36.38587 ], [ -114.042843000000104, 36.448175 ], [ -114.043133, 36.469716 ], [ -114.044816, 36.491343 ], [ -114.045647, 36.521095 ], [ -114.04632, 36.564615 ], [ -114.049935, 36.709521 ], [ -114.049973, 36.738672 ], [ -114.050327, 36.752899 ], [ -114.049879, 36.781909 ], [ -114.050502, 36.895232 ], [ -114.049995, 36.957769 ], [ -114.050600000000102, 37.000396 ], [ -114.0008, 37.000448 ], [ -113.96266, 36.999973 ], [ -113.052912, 36.999983 ], [ -112.875756, 37.000533 ], [ -112.538546, 37.000652 ], [ -112.529846, 37.000899 ], [ -112.36102, 37.001114 ], [ -112.36037, 37.000912 ], [ -112.359329, 37.001117 ], [ -112.125741, 37.001237 ], [ -112.000735, 37.000959 ], [ -111.62572, 37.001401 ], [ -111.616249, 37.001647 ], [ -111.406146, 37.001481 ], [ -111.405895, 37.001702 ], [ -111.313211, 37.000894 ], [ -111.312169, 37.001193 ], [ -111.305843, 37.000776 ], [ -111.278221, 37.000467 ], [ -111.254853, 37.001076 ], [ -111.133718, 37.000779 ], [ -111.081493, 37.002261 ], [ -111.052354, 37.00246 ], [ -111.00182, 37.002293 ], [ -110.625691, 37.003725 ], [ -110.625605, 37.003416 ], [ -110.599512, 37.003448 ], [ -110.509004, 37.003985 ], [ -110.50069, 37.00426 ], [ -110.490908, 37.003566 ], [ -110.478446, 36.999996 ], [ -110.47729, 36.999997 ], [ -110.47019, 36.997997 ], [ -110.023043, 36.998601 ], [ -110.000876, 36.998502 ], [ -110.000677, 36.997968 ], [ -109.969958, 36.997949 ], [ -109.938511, 36.998491 ], [ -109.750669, 36.99816 ], [ -109.743284, 36.998453 ], [ -109.625658, 36.998308 ], [ -109.495338, 36.999105 ], [ -109.362565, 36.999304 ], [ -109.125691, 36.999389 ], [ -109.045223, 36.999084 ], [ -109.045554, 36.645013 ], [ -109.04539, 36.503241 ], [ -109.045946, 36.375002 ], [ -109.045637, 36.374625 ], [ -109.045744, 36.257214 ], [ -109.046024, 36.247197 ], [ -109.045877, 36.188719 ], [ -109.046183, 36.181751 ], [ -109.045726, 36.116908 ], [ -109.045767, 36.033679 ], [ -109.046124, 35.990618 ], [ -109.046009, 35.875012 ], [ -109.046423, 35.624911 ], [ -109.046181, 35.614569 ], [ -109.046795, 35.379918 ], [ -109.046084, 35.249986 ], [ -109.046256, 35.125041 ], [ -109.045842, 34.966076 ], [ -109.046136, 34.875006 ], [ -109.046072, 34.828566 ], [ -109.045626, 34.814226 ], [ -109.046104, 34.799981 ], [ -109.045363, 34.785406 ], [ -109.046087, 34.770963 ], [ -109.046175, 34.520102 ], [ -109.046561, 34.379479 ], [ -109.046337, 34.283639 ], [ -109.046664, 34.250046 ], [ -109.04696, 34.068968 ], [ -109.047006, 34.00005 ], [ -109.046426, 33.875052 ], [ -109.046869, 33.844183 ], [ -109.047145, 33.74001 ], [ -109.046662, 33.625055 ], [ -109.046825, 33.469389 ], [ -109.047309, 33.462131 ], [ -109.046928, 33.4428 ], [ -109.047304, 33.439442 ], [ -109.047298, 33.409774 ], [ -109.046564, 33.375059 ], [ -109.047045, 33.36928 ], [ -109.046827, 33.365271 ], [ -109.047104, 33.27046 ], [ -109.04747, 33.250168 ], [ -109.047122, 33.2408 ], [ -109.047324, 33.18408 ], [ -109.047208, 33.107377 ], [ -109.046905, 33.091931 ], [ -109.047513, 33.059137 ], [ -109.047382, 33.000311 ], [ -109.04711, 32.99225 ], [ -109.047117, 32.777569 ], [ -109.047518, 32.749997 ], [ -109.047796, 32.68263 ], [ -109.047912, 32.500261 ], [ -109.047629, 32.413987 ], [ -109.048323, 32.070887 ], [ -109.048731, 32.028174 ], [ -109.048465, 32.000089 ], [ -109.048738, 31.876905 ], [ -109.049048, 31.870689 ], [ -109.049298, 31.796742 ], [ -109.04899, 31.721922 ], [ -109.049311, 31.544932 ], [ -109.050173, 31.480004 ], [ -109.049934, 31.437907 ], [ -109.050044, 31.332502 ], [ -109.1256, 31.332685 ], [ -109.271744, 31.333942 ], [ -109.49449, 31.334125 ], [ -109.500621, 31.333911 ], [ -109.875628, 31.33405 ], [ -110.000613, 31.333145 ], [ -110.140512, 31.333965 ], [ -110.375635, 31.332896 ], [ -110.460172, 31.332827 ], [ -110.68143, 31.33309 ], [ -110.750638, 31.333636 ], [ -110.795467, 31.33363 ], [ -110.94232, 31.332833 ], [ -111.000643, 31.332177 ], [ -111.074825, 31.332239 ], [ -111.125646, 31.348978 ], [ -111.129451, 31.349979 ], [ -111.357436, 31.423346 ], [ -111.500659, 31.468862 ], [ -111.560194, 31.488138 ], [ -111.659998, 31.519448 ], [ -111.738873, 31.544718 ], [ -111.875674, 31.587657 ], [ -111.979304, 31.620648 ], [ -112.200717, 31.690033 ], [ -112.365328, 31.741078 ], [ -112.375759, 31.743987 ], [ -112.399254, 31.751638 ], [ -112.433246, 31.762162 ], [ -112.737399, 31.855527 ], [ -112.800213, 31.87507 ], [ -112.834233, 31.885137 ], [ -112.871505, 31.896838 ], [ -113.125961, 31.97278 ], [ -113.21163, 32.000061 ], [ -113.211365, 32.000061 ], [ -113.217307, 32.002106 ], [ -113.250731, 32.012405 ], [ -113.493196, 32.088943 ], [ -113.750756, 32.169005 ], [ -113.78168, 32.179034 ], [ -114.250775, 32.323909 ], [ -114.625785, 32.43789 ], [ -114.790245, 32.487505 ], [ -114.813613, 32.494276 ], [ -114.813991000000101, 32.497231 ], [ -114.812316, 32.500054 ], [ -114.813402, 32.501764 ], [ -114.813753000000105, 32.50426 ], [ -114.815185, 32.506023 ], [ -114.81651, 32.506963 ], [ -114.816591000000102, 32.507696 ], [ -114.815591, 32.508612 ], [ -114.814321000000106, 32.509023 ], [ -114.812942, 32.509116 ], [ -114.810159, 32.508383 ], [ -114.807726, 32.508726 ], [ -114.804076, 32.510375 ], [ -114.802833, 32.511749 ], [ -114.802211, 32.513191 ], [ -114.802238, 32.515206 ], [ -114.80367, 32.516374 ], [ -114.807753, 32.516925 ], [ -114.809672, 32.517567 ], [ -114.810374, 32.518391 ], [ -114.809969, 32.520291 ], [ -114.810482, 32.521758 ], [ -114.810969, 32.522444 ], [ -114.812888, 32.52359 ], [ -114.813348000000104, 32.524186 ], [ -114.812645, 32.525399 ], [ -114.811293, 32.526429 ], [ -114.810563, 32.527666 ], [ -114.808617, 32.529017 ], [ -114.80640000000011, 32.531191 ], [ -114.804858, 32.533689 ], [ -114.802559, 32.535521 ], [ -114.802181, 32.536414 ], [ -114.802018, 32.53946 ], [ -114.80237, 32.540078 ], [ -114.804776000000103, 32.541659 ], [ -114.805966, 32.545346 ], [ -114.8058300000001, 32.546354 ], [ -114.803883, 32.548001 ], [ -114.795635, 32.550956 ], [ -114.793769, 32.552329 ], [ -114.792065, 32.555009 ], [ -114.791551, 32.557023 ], [ -114.791523, 32.558602 ], [ -114.792955000000106, 32.562085 ], [ -114.792088, 32.568497 ], [ -114.792358000000107, 32.569091 ], [ -114.793224, 32.569459 ], [ -114.794684, 32.568703 ], [ -114.795253, 32.56662 ], [ -114.79766, 32.564444 ], [ -114.801311, 32.562865 ], [ -114.803664, 32.560689 ], [ -114.806830000000105, 32.55888 ], [ -114.808885, 32.558467 ], [ -114.810318, 32.558628 ], [ -114.812914, 32.560049 ], [ -114.813995, 32.562201 ], [ -114.814212, 32.56369 ], [ -114.813968, 32.566209 ], [ -114.812995, 32.568706 ], [ -114.81148, 32.569781 ], [ -114.804421, 32.572941 ], [ -114.803474, 32.573628 ], [ -114.801877, 32.576009 ], [ -114.801471, 32.578255 ], [ -114.80193, 32.579194 ], [ -114.803879, 32.580889 ], [ -114.803987, 32.582652 ], [ -114.802823, 32.585079 ], [ -114.800441, 32.588079 ], [ -114.799737, 32.592177 ], [ -114.799683, 32.593621 ], [ -114.801251, 32.596232 ], [ -114.801548, 32.598591 ], [ -114.802361, 32.59937 ], [ -114.805932, 32.600721 ], [ -114.8069050000001, 32.60143 ], [ -114.808041, 32.603172 ], [ -114.807879, 32.605416 ], [ -114.809042, 32.608806 ], [ -114.808906, 32.612951 ], [ -114.809555, 32.616203 ], [ -114.808662, 32.619157 ], [ -114.80739, 32.621332 ], [ -114.806821, 32.621721 ], [ -114.799302, 32.625115 ], [ -114.797564, 32.624578 ], [ -114.794102, 32.622475 ], [ -114.792640000000105, 32.621948 ], [ -114.791179, 32.621833 ], [ -114.787715, 32.623573 ], [ -114.782573, 32.624304 ], [ -114.781896, 32.624702 ], [ -114.781766, 32.625613 ], [ -114.782518, 32.628625 ], [ -114.782235, 32.630215 ], [ -114.779215, 32.633578 ], [ -114.77457, 32.63593 ], [ -114.771978, 32.637954 ], [ -114.768199, 32.639874 ], [ -114.764382, 32.642666 ], [ -114.76331, 32.644616 ], [ -114.763512, 32.645995 ], [ -114.764917, 32.648079 ], [ -114.76495, 32.649391 ], [ -114.75831, 32.655178 ], [ -114.751079, 32.659789 ], [ -114.749480000000105, 32.66178 ], [ -114.748000000000104, 32.664184 ], [ -114.748183, 32.665098 ], [ -114.747817, 32.667777 ], [ -114.746383, 32.669853 ], [ -114.745344, 32.67219 ], [ -114.7449, 32.677231 ], [ -114.744349, 32.678935 ], [ -114.740541, 32.684196 ], [ -114.739405, 32.686385 ], [ -114.730453, 32.698844 ], [ -114.72981, 32.700282 ], [ -114.72974, 32.703121 ], [ -114.730086, 32.704298 ], [ -114.728408, 32.706648 ], [ -114.726974, 32.707875 ], [ -114.72534, 32.710369 ], [ -114.72241, 32.713597 ], [ -114.719938, 32.71829 ], [ -114.717695, 32.721547 ], [ -114.715788, 32.727758 ], [ -114.714522, 32.73039 ], [ -114.712629, 32.732678 ], [ -114.710615, 32.733936 ], [ -114.709074, 32.735456 ], [ -114.706114, 32.740986 ], [ -114.70294, 32.744793 ], [ -114.701582000000101, 32.745632 ], [ -114.699247, 32.745098 ], [ -114.695387, 32.742244 ], [ -114.691801, 32.740147 ], [ -114.689282, 32.737927 ], [ -114.688230000000104, 32.73753 ], [ -114.682614, 32.737348 ], [ -114.672025, 32.734951 ], [ -114.665921, 32.734028 ], [ -114.654247, 32.73357 ], [ -114.645353, 32.732139 ], [ -114.635006000000104, 32.731372 ], [ -114.629299, 32.729908 ], [ -114.617479, 32.728243 ], [ -114.61567, 32.728454 ], [ -114.61587, 32.729717 ], [ -114.615501, 32.730044 ], [ -114.615504, 32.731449 ], [ -114.614786, 32.732846 ], [ -114.614787000000106, 32.734076 ], [ -114.615112, 32.734515 ], [ -114.581784, 32.734946 ], [ -114.581736, 32.74232 ], [ -114.564508, 32.742274 ], [ -114.564447, 32.749554 ], [ -114.539224, 32.749812 ], [ -114.539092, 32.756949 ], [ -114.526856, 32.757094 ], [ -114.528443, 32.767276 ], [ -114.529264, 32.769484 ], [ -114.531831, 32.774264 ], [ -114.532432, 32.776922 ], [ -114.532426, 32.778644 ], [ -114.531746, 32.782503 ], [ -114.531669, 32.791185 ], [ -114.529633000000103, 32.795477 ], [ -114.522031, 32.801675 ], [ -114.520385, 32.803576 ], [ -114.520363000000103, 32.804385 ], [ -114.519758, 32.805676 ], [ -114.515389, 32.811439 ], [ -114.510327, 32.816488 ], [ -114.494116, 32.823287 ], [ -114.475892, 32.838693 ], [ -114.468971, 32.845155 ], [ -114.465711, 32.873681 ], [ -114.465172, 32.885295 ], [ -114.463307, 32.899116 ], [ -114.462929, 32.907944 ], [ -114.46365, 32.911682 ], [ -114.464448, 32.913128 ], [ -114.473713, 32.920594 ], [ -114.47664, 32.923628 ], [ -114.477952000000101, 32.925706 ], [ -114.479005, 32.928291 ], [ -114.480783, 32.933678 ], [ -114.480925, 32.936276 ], [ -114.48074, 32.937027 ], [ -114.478456, 32.940555 ], [ -114.474042, 32.94515 ], [ -114.470768, 32.949424 ], [ -114.468536, 32.953922 ], [ -114.467624, 32.956663 ], [ -114.467274, 32.960172 ], [ -114.467367, 32.965384 ], [ -114.468379, 32.970745 ], [ -114.468995, 32.972239 ], [ -114.470511, 32.973858 ], [ -114.472606, 32.974654 ], [ -114.475171, 32.975154 ], [ -114.477308, 32.975023 ], [ -114.479477, 32.974189 ], [ -114.480831, 32.973362 ], [ -114.481315, 32.972064 ], [ -114.484806, 32.971339 ], [ -114.488625, 32.969946 ], [ -114.490129, 32.969884 ], [ -114.492184, 32.971021 ], [ -114.492938, 32.971781 ], [ -114.494212, 32.974262 ], [ -114.495712, 32.980075 ], [ -114.496798, 32.986534 ], [ -114.497052, 32.990206 ], [ -114.49941, 33.00004 ], [ -114.499797, 33.003905 ], [ -114.50287, 33.011154 ], [ -114.506129, 33.017009 ], [ -114.507956, 33.019708 ], [ -114.511343, 33.023455 ], [ -114.5149, 33.026524 ], [ -114.52013, 33.029984 ], [ -114.523578, 33.03096 ], [ -114.538459, 33.033422 ], [ -114.553189, 33.033974 ], [ -114.56085, 33.035285 ], [ -114.5648, 33.035077 ], [ -114.571653, 33.036624 ], [ -114.575161, 33.036541 ], [ -114.578287, 33.035375 ], [ -114.581404, 33.032545 ], [ -114.584765, 33.02823 ], [ -114.586982, 33.026944 ], [ -114.589778, 33.026228 ], [ -114.598093, 33.025384 ], [ -114.601014, 33.02541 ], [ -114.611584, 33.026221 ], [ -114.618788, 33.027202 ], [ -114.625787, 33.029435 ], [ -114.628294, 33.03105 ], [ -114.629732, 33.032546 ], [ -114.63419, 33.039024 ], [ -114.639552, 33.04529 ], [ -114.641621, 33.046894 ], [ -114.64482, 33.048644 ], [ -114.645979, 33.048902 ], [ -114.647049, 33.048416 ], [ -114.649001, 33.046762 ], [ -114.650999, 33.044131 ], [ -114.655038000000104, 33.037106 ], [ -114.657827, 33.033824 ], [ -114.659832, 33.032664 ], [ -114.662317, 33.03267 ], [ -114.66506, 33.033906 ], [ -114.670803, 33.037983 ], [ -114.673659, 33.041896 ], [ -114.67483, 33.045507 ], [ -114.675103000000107, 33.04753 ], [ -114.674295, 33.057169 ], [ -114.679114, 33.061966 ], [ -114.686991, 33.070968 ], [ -114.68912, 33.076121 ], [ -114.689307, 33.079179 ], [ -114.688597000000101, 33.082869 ], [ -114.68902, 33.084035 ], [ -114.692548000000102, 33.085786 ], [ -114.694628, 33.086226 ], [ -114.701165000000103, 33.086368 ], [ -114.70473, 33.087051 ], [ -114.706488, 33.08816 ], [ -114.707819, 33.091102 ], [ -114.708133000000103, 33.094022 ], [ -114.707896000000105, 33.097431 ], [ -114.706175, 33.105334 ], [ -114.703682, 33.113768 ], [ -114.696914, 33.131119 ], [ -114.694858, 33.13346 ], [ -114.690246, 33.137724 ], [ -114.687405, 33.141983 ], [ -114.684907, 33.147823 ], [ -114.682759, 33.154808 ], [ -114.679945, 33.159059 ], [ -114.67935, 33.162433 ], [ -114.68089, 33.169074 ], [ -114.680237, 33.169637 ], [ -114.679115, 33.174608 ], [ -114.675830000000104, 33.18152 ], [ -114.6753590000001, 33.185488 ], [ -114.675189, 33.188178 ], [ -114.678163, 33.199488 ], [ -114.678749, 33.203448 ], [ -114.676072, 33.210835 ], [ -114.673715, 33.219245 ], [ -114.673626, 33.223121 ], [ -114.674479000000105, 33.225504 ], [ -114.678097, 33.2303 ], [ -114.682731, 33.234918 ], [ -114.689421, 33.24525 ], [ -114.689541, 33.246428 ], [ -114.688205, 33.247965 ], [ -114.683253, 33.250034 ], [ -114.67766, 33.254426 ], [ -114.674491000000103, 33.255597 ], [ -114.672924, 33.257042 ], [ -114.672088, 33.258499 ], [ -114.672401, 33.260469 ], [ -114.677032, 33.270169 ], [ -114.680507, 33.273576 ], [ -114.684363000000104, 33.276023 ], [ -114.688599, 33.277861 ], [ -114.694449, 33.279785 ], [ -114.702873, 33.281916 ], [ -114.711197, 33.283341 ], [ -114.717875, 33.285156 ], [ -114.72167, 33.286982 ], [ -114.723259, 33.288079 ], [ -114.731223, 33.302433 ], [ -114.731222000000102, 33.304039 ], [ -114.729904000000104, 33.305745 ], [ -114.726484, 33.308273 ], [ -114.724665000000101, 33.310097 ], [ -114.723623000000103, 33.312109 ], [ -114.71861, 33.315761 ], [ -114.710627, 33.3205 ], [ -114.70787, 33.323316 ], [ -114.705186, 33.327709 ], [ -114.700938, 33.337014 ], [ -114.69935, 33.345692 ], [ -114.699124, 33.349258 ], [ -114.698035, 33.352442 ], [ -114.69817, 33.356575 ], [ -114.699056, 33.361148 ], [ -114.701959, 33.367134 ], [ -114.704201, 33.371238 ], [ -114.706722, 33.37503 ], [ -114.707348, 33.376627 ], [ -114.707485000000105, 33.378375 ], [ -114.707009, 33.380633 ], [ -114.707309, 33.38254 ], [ -114.708407, 33.384142 ], [ -114.713602, 33.388256 ], [ -114.72425, 33.40042 ], [ -114.725292, 33.402341 ], [ -114.725535, 33.404055 ], [ -114.725282, 33.405048 ], [ -114.723829, 33.406531 ], [ -114.722201, 33.407384 ], [ -114.720065000000105, 33.407891 ], [ -114.710878, 33.407254 ], [ -114.701788, 33.408377 ], [ -114.697708, 33.410942 ], [ -114.696805, 33.412087 ], [ -114.696507, 33.414063 ], [ -114.695658, 33.415128 ], [ -114.68795, 33.417934 ], [ -114.673691, 33.419157 ], [ -114.658254, 33.413021 ], [ -114.656735, 33.412813 ], [ -114.652828, 33.412923 ], [ -114.64954, 33.413633 ], [ -114.643302, 33.416746 ], [ -114.635183, 33.422725 ], [ -114.633262, 33.425024 ], [ -114.630903, 33.426754 ], [ -114.62964, 33.428137 ], [ -114.627479, 33.432307 ], [ -114.622283, 33.447558 ], [ -114.622519, 33.450879 ], [ -114.623395000000102, 33.45449 ], [ -114.622918, 33.456561 ], [ -114.618354, 33.462708 ], [ -114.614331, 33.467315 ], [ -114.6137820000001, 33.469049 ], [ -114.612472, 33.470768 ], [ -114.607843000000102, 33.474834 ], [ -114.603396000000103, 33.480631 ], [ -114.601694, 33.481396 ], [ -114.599712, 33.484316 ], [ -114.597283000000104, 33.490653 ], [ -114.593721, 33.495932 ], [ -114.592369, 33.498675 ], [ -114.589246, 33.501813 ], [ -114.580468, 33.506465 ], [ -114.573757, 33.507543 ], [ -114.569533, 33.509219 ], [ -114.560963, 33.516739 ], [ -114.560552, 33.518272 ], [ -114.560835, 33.524334 ], [ -114.560098, 33.526663 ], [ -114.559507, 33.530724 ], [ -114.558898, 33.531819 ], [ -114.542011, 33.542481 ], [ -114.531802, 33.547862 ], [ -114.530401, 33.550099 ], [ -114.525997000000103, 33.551457 ], [ -114.524599, 33.552231 ], [ -114.524215, 33.553068 ], [ -114.52822, 33.559318 ], [ -114.531613, 33.561702 ], [ -114.532333, 33.562879 ], [ -114.533192, 33.565823 ], [ -114.535965000000104, 33.569154 ], [ -114.536784, 33.570959 ], [ -114.537801, 33.575555 ], [ -114.538983, 33.576792 ], [ -114.5403, 33.580615 ], [ -114.540652, 33.582872 ], [ -114.540111, 33.588354 ], [ -114.540664, 33.589789 ], [ -114.540617, 33.591412 ], [ -114.537493, 33.594895 ], [ -114.536777, 33.596394 ], [ -114.531051, 33.604482 ], [ -114.529186, 33.60665 ], [ -114.526782, 33.608831 ], [ -114.523994, 33.60999 ], [ -114.522071, 33.611277 ], [ -114.521845, 33.612544 ], [ -114.522367, 33.614172 ], [ -114.527378, 33.617828 ], [ -114.528578, 33.619994 ], [ -114.52908, 33.621711 ], [ -114.531215, 33.623913 ], [ -114.531034, 33.628213 ], [ -114.530311, 33.629037 ], [ -114.52637, 33.630259 ], [ -114.523802, 33.6347 ], [ -114.525394, 33.640669 ], [ -114.529549000000102, 33.643861 ], [ -114.533215, 33.648443 ], [ -114.533194, 33.65166 ], [ -114.532164, 33.653194 ], [ -114.530583, 33.654461 ], [ -114.525163, 33.655939 ], [ -114.518337, 33.655927 ], [ -114.514559000000105, 33.658014 ], [ -114.514057, 33.660179 ], [ -114.515336, 33.662033 ], [ -114.517112, 33.662877 ], [ -114.520671, 33.662681 ], [ -114.526439, 33.66388 ], [ -114.530267, 33.666821 ], [ -114.532123, 33.669702 ], [ -114.531523, 33.675108 ], [ -114.530348, 33.679245 ], [ -114.527782, 33.682684 ], [ -114.523959, 33.685879 ], [ -114.519113, 33.688473 ], [ -114.512409, 33.691282 ], [ -114.507996, 33.692018 ], [ -114.504993, 33.693022 ], [ -114.502899, 33.694255 ], [ -114.496489, 33.696901 ], [ -114.495719, 33.698454 ], [ -114.495537, 33.701506 ], [ -114.494407, 33.705395 ], [ -114.494197, 33.707922 ], [ -114.494901, 33.71443 ], [ -114.496565, 33.719155 ], [ -114.498133, 33.720634 ], [ -114.500788, 33.722204 ], [ -114.502661, 33.724584 ], [ -114.504176, 33.728055 ], [ -114.506799, 33.730518 ], [ -114.510265, 33.732146 ], [ -114.512348000000102, 33.734214 ], [ -114.510777, 33.737574 ], [ -114.508206, 33.741587 ], [ -114.506, 33.746344 ], [ -114.504483, 33.750998 ], [ -114.50434, 33.756381 ], [ -114.504863, 33.760465 ], [ -114.507089, 33.76793 ], [ -114.516734, 33.788345 ], [ -114.518942, 33.797302 ], [ -114.521555, 33.801982 ], [ -114.524682, 33.808961 ], [ -114.527188, 33.812639 ], [ -114.52805, 33.814963 ], [ -114.527886, 33.815617 ], [ -114.527161, 33.816191 ], [ -114.522714, 33.818979 ], [ -114.520733, 33.822031 ], [ -114.51997, 33.825381 ], [ -114.520465, 33.827778 ], [ -114.523409, 33.835323 ], [ -114.525539, 33.838614 ], [ -114.529597, 33.848063 ], [ -114.530607, 33.85544 ], [ -114.529883, 33.857563 ], [ -114.527069, 33.859429 ], [ -114.525666, 33.860003 ], [ -114.524292, 33.860133 ], [ -114.52287, 33.859965 ], [ -114.518998, 33.858563 ], [ -114.516811000000104, 33.85812 ], [ -114.514673, 33.858638 ], [ -114.511346, 33.86157 ], [ -114.506635, 33.863484 ], [ -114.505638, 33.864276 ], [ -114.503887, 33.865754 ], [ -114.503104, 33.867166 ], [ -114.503017, 33.867998 ], [ -114.503860000000103, 33.871234 ], [ -114.503395, 33.875018 ], [ -114.50434, 33.876882 ], [ -114.510138, 33.880777 ], [ -114.51866, 33.888263 ], [ -114.522768, 33.892583 ], [ -114.524813, 33.895684 ], [ -114.525872, 33.901008 ], [ -114.52569, 33.901428 ], [ -114.524289, 33.901587 ], [ -114.516344, 33.897918 ], [ -114.513715, 33.897959 ], [ -114.510944, 33.899099 ], [ -114.508708, 33.90064 ], [ -114.507988, 33.901813 ], [ -114.50792, 33.903807 ], [ -114.508558, 33.906098 ], [ -114.511511, 33.911092 ], [ -114.514503, 33.914214 ], [ -114.518434, 33.917518 ], [ -114.523393, 33.921221 ], [ -114.525361, 33.922272 ], [ -114.528385, 33.923674 ], [ -114.531107, 33.924633 ], [ -114.534146, 33.925187 ], [ -114.534951, 33.9257 ], [ -114.535853, 33.928103 ], [ -114.535478, 33.934651 ], [ -114.530566, 33.943629 ], [ -114.52868, 33.947817 ], [ -114.526353, 33.950917 ], [ -114.522002, 33.955623 ], [ -114.51586, 33.958106 ], [ -114.51497, 33.958149 ], [ -114.511231, 33.95704 ], [ -114.509568, 33.957264 ], [ -114.499883, 33.961789 ], [ -114.496042, 33.96589 ], [ -114.490398, 33.97062 ], [ -114.488459, 33.972832 ], [ -114.484784, 33.975519 ], [ -114.483097, 33.977745 ], [ -114.482333, 33.980181 ], [ -114.481455, 33.981261 ], [ -114.475907, 33.984424 ], [ -114.471138, 33.98804 ], [ -114.467932, 33.992877 ], [ -114.466187, 33.993465 ], [ -114.461133, 33.993541 ], [ -114.46012, 33.993888 ], [ -114.459258, 33.994711 ], [ -114.458028, 33.997158 ], [ -114.458026000000103, 33.99782 ], [ -114.459184, 34.000016 ], [ -114.460689, 34.001128 ], [ -114.46628, 34.003885 ], [ -114.46731, 34.00519 ], [ -114.467404, 34.00745 ], [ -114.465867000000102, 34.010987 ], [ -114.464525, 34.011982 ], [ -114.463336, 34.012259 ], [ -114.454807, 34.010968 ], [ -114.450206, 34.012574 ], [ -114.446815, 34.01421 ], [ -114.443821, 34.016176 ], [ -114.44054, 34.019329 ], [ -114.438266, 34.022609 ], [ -114.436171, 34.028083 ], [ -114.434949, 34.037784 ], [ -114.435816, 34.04373 ], [ -114.438602, 34.050205 ], [ -114.439406, 34.05381 ], [ -114.43934, 34.057893 ], [ -114.437683, 34.071937 ], [ -114.435907, 34.077491 ], [ -114.434181, 34.087379 ], [ -114.43338, 34.088413 ], [ -114.428026, 34.092787 ], [ -114.426168, 34.097042 ], [ -114.422899, 34.099661 ], [ -114.420499, 34.103466 ], [ -114.415908, 34.107636 ], [ -114.41168, 34.110031 ], [ -114.405916, 34.111468 ], [ -114.401336, 34.111638 ], [ -114.390565, 34.110084 ], [ -114.379223, 34.11599 ], [ -114.369292000000101, 34.117519 ], [ -114.366517, 34.118577 ], [ -114.360402, 34.123577 ], [ -114.359389, 34.125016 ], [ -114.358358, 34.127617 ], [ -114.356372, 34.130428 ], [ -114.35303, 34.13312 ], [ -114.350478, 34.134107 ], [ -114.348051, 34.134457 ], [ -114.336112, 34.134034 ], [ -114.324576, 34.136759 ], [ -114.320777, 34.138635 ], [ -114.312206, 34.144776 ], [ -114.307802, 34.150574 ], [ -114.298168, 34.160321 ], [ -114.292806, 34.166725 ], [ -114.287294, 34.170529 ], [ -114.275267, 34.172149 ], [ -114.26846, 34.170177 ], [ -114.257034, 34.172837 ], [ -114.253444000000101, 34.174129 ], [ -114.244421, 34.179403 ], [ -114.240712000000102, 34.183232 ], [ -114.229715, 34.186928 ], [ -114.227034, 34.188866 ], [ -114.225814, 34.191238 ], [ -114.224941, 34.193896 ], [ -114.225075, 34.196814 ], [ -114.22579, 34.199236 ], [ -114.225861, 34.201774 ], [ -114.225194, 34.203642 ], [ -114.223384, 34.205136 ], [ -114.215454, 34.208956 ], [ -114.211761, 34.211539 ], [ -114.208253, 34.215505 ], [ -114.190876, 34.230858 ], [ -114.17805, 34.239969 ], [ -114.176403, 34.241512 ], [ -114.175948, 34.242695 ], [ -114.175906, 34.245587 ], [ -114.174597, 34.247303 ], [ -114.166536, 34.249647 ], [ -114.166124, 34.250015 ], [ -114.164476, 34.251667 ], [ -114.163867, 34.253349 ], [ -114.163959, 34.255377 ], [ -114.165335, 34.258486 ], [ -114.165249, 34.259125 ], [ -114.164648, 34.259699 ], [ -114.156853, 34.258415 ], [ -114.153346, 34.258289 ], [ -114.147159, 34.259564 ], [ -114.144779, 34.259623 ], [ -114.13545, 34.257886 ], [ -114.133264, 34.258462 ], [ -114.131489000000101, 34.260387 ], [ -114.131211, 34.26273 ], [ -114.134768, 34.268965 ], [ -114.136671, 34.274377 ], [ -114.137045, 34.277018 ], [ -114.13605, 34.280833 ], [ -114.136677, 34.283936 ], [ -114.138365, 34.288564 ], [ -114.139534, 34.295844 ], [ -114.139187, 34.298074 ], [ -114.138167, 34.300936 ], [ -114.138282, 34.30323 ], [ -114.14093, 34.305919 ], [ -114.157206, 34.317862 ], [ -114.157939, 34.320277 ], [ -114.164249, 34.330816 ], [ -114.168807, 34.339513 ], [ -114.172845, 34.344979 ], [ -114.176909, 34.349306 ], [ -114.181145, 34.352186 ], [ -114.185556, 34.354386 ], [ -114.191094, 34.356125 ], [ -114.19648, 34.359187 ], [ -114.199482, 34.361373 ], [ -114.213774, 34.36246 ], [ -114.226107, 34.365916 ], [ -114.229686, 34.368908 ], [ -114.233065, 34.375013 ], [ -114.234275, 34.376662 ], [ -114.245261, 34.385659 ], [ -114.248649, 34.388113 ], [ -114.252739, 34.3901 ], [ -114.25822, 34.395046 ], [ -114.262909, 34.400373 ], [ -114.264317000000105, 34.401329 ], [ -114.267521, 34.402486 ], [ -114.272184, 34.402961 ], [ -114.280108, 34.403147 ], [ -114.282261, 34.403641 ], [ -114.286802, 34.40534 ], [ -114.288663, 34.406623 ], [ -114.290219, 34.408291 ], [ -114.291751, 34.411104 ], [ -114.291903, 34.416231 ], [ -114.292226, 34.417606 ], [ -114.294836, 34.421389 ], [ -114.301016000000104, 34.426807 ], [ -114.308659, 34.430485 ], [ -114.312251, 34.432726 ], [ -114.319054, 34.435831 ], [ -114.32613, 34.437251 ], [ -114.32688, 34.438048 ], [ -114.330669, 34.445295 ], [ -114.332991, 34.448082 ], [ -114.335372, 34.450038 ], [ -114.339627, 34.451435 ], [ -114.342615, 34.451442 ], [ -114.348974, 34.450166 ], [ -114.356025, 34.449744 ], [ -114.363404000000102, 34.447773 ], [ -114.373719, 34.446938 ], [ -114.375789, 34.447798 ], [ -114.378852, 34.450376 ], [ -114.382985, 34.453971 ], [ -114.386699, 34.457911 ], [ -114.387407, 34.460492 ], [ -114.387187, 34.462021 ], [ -114.383525, 34.470405 ], [ -114.381701, 34.47604 ], [ -114.381555, 34.477883 ], [ -114.383038, 34.488903 ], [ -114.382358, 34.495758 ], [ -114.381402, 34.499245 ], [ -114.378124, 34.507288 ], [ -114.378223, 34.516521 ], [ -114.380838, 34.529724 ], [ -114.389603, 34.542982 ], [ -114.398847, 34.559149 ], [ -114.405228, 34.569637 ], [ -114.422382, 34.580711 ], [ -114.435671, 34.593841 ], [ -114.43681, 34.596074 ], [ -114.436363, 34.596797 ], [ -114.427502, 34.599227 ], [ -114.425338, 34.600842 ], [ -114.424326, 34.602338 ], [ -114.424202, 34.610453 ], [ -114.428648, 34.614641 ], [ -114.438739, 34.621455 ], [ -114.439495, 34.625858 ], [ -114.441398, 34.630171 ], [ -114.441525, 34.631529 ], [ -114.440685, 34.634739 ], [ -114.440294, 34.63824 ], [ -114.440519, 34.640066 ], [ -114.441465, 34.64253 ], [ -114.444276, 34.646542 ], [ -114.445664, 34.647542 ], [ -114.449549, 34.651423 ], [ -114.457985, 34.657113 ], [ -114.45821, 34.657994 ], [ -114.457702, 34.659328 ], [ -114.457185, 34.659992 ], [ -114.451785, 34.663891 ], [ -114.450614, 34.665793 ], [ -114.450506, 34.666836 ], [ -114.451532, 34.668605 ], [ -114.454305, 34.671234 ], [ -114.45491, 34.673092 ], [ -114.454881, 34.675639 ], [ -114.455536, 34.677335 ], [ -114.458163, 34.681161 ], [ -114.462178, 34.6858 ], [ -114.463633, 34.68794 ], [ -114.465246, 34.691202 ], [ -114.46809, 34.701786 ], [ -114.46813, 34.704445 ], [ -114.46862, 34.707573 ], [ -114.470477, 34.711368 ], [ -114.47162, 34.712966 ], [ -114.473682, 34.713964 ], [ -114.477297, 34.714514 ], [ -114.482779, 34.714511 ], [ -114.487508, 34.716626 ], [ -114.489287, 34.720155 ], [ -114.490971, 34.724848 ], [ -114.492017, 34.725702 ], [ -114.495858, 34.727956 ], [ -114.499007, 34.729096 ], [ -114.500795, 34.730418 ], [ -114.510292, 34.733582 ], [ -114.514178, 34.735288 ], [ -114.516619, 34.736745 ], [ -114.521048, 34.741173 ], [ -114.522619, 34.74373 ], [ -114.525611, 34.747005 ], [ -114.529079, 34.750006 ], [ -114.529615, 34.750822 ], [ -114.540306, 34.757109 ], [ -114.546884, 34.761802 ], [ -114.552682, 34.766871 ], [ -114.558653, 34.773852 ], [ -114.563979, 34.782597 ], [ -114.565184, 34.785976 ], [ -114.569383, 34.791568 ], [ -114.571010000000101, 34.794294 ], [ -114.574474, 34.804214 ], [ -114.574694, 34.807471 ], [ -114.576452, 34.8153 ], [ -114.578681000000103, 34.820977 ], [ -114.581126, 34.826115 ], [ -114.586842, 34.835672 ], [ -114.592339, 34.841153 ], [ -114.600653, 34.847361 ], [ -114.604255, 34.849573 ], [ -114.619878, 34.856873 ], [ -114.623939, 34.859738 ], [ -114.628276, 34.863596 ], [ -114.630682000000107, 34.866352 ], [ -114.633051, 34.869971 ], [ -114.634382, 34.87289 ], [ -114.635176, 34.875003 ], [ -114.635458, 34.876902 ] ] ] ] } +` diff --git a/cmd/tile38-benchmark/main.go b/cmd/tile38-benchmark/main.go index 972ac6a0..7f613374 100644 --- a/cmd/tile38-benchmark/main.go +++ b/cmd/tile38-benchmark/main.go @@ -8,10 +8,13 @@ import ( "os" "strconv" "strings" + "sync" "sync/atomic" "time" "github.com/tidwall/redbench" + "github.com/tidwall/redcon" + "github.com/tidwall/tile38/cmd/tile38-benchmark/az" "github.com/tidwall/tile38/core" ) @@ -280,8 +283,9 @@ func main() { ) } case "INTERSECTS", - "INTERSECTS-RECT", "INTERSECTS-RECT-1000", "INTERSECTS-RECT-10000", "INTERSECTS-RECT-100000", - "INTERSECTS-CIRCLE", "INTERSECTS-CIRCLE-1000", "INTERSECTS-CIRCLE-10000", "INTERSECTS-CIRCLE-100000": + "INTERSECTS-BOUNDS", "INTERSECTS-BOUNDS-1000", "INTERSECTS-BOUNDS-10000", "INTERSECTS-BOUNDS-100000", + "INTERSECTS-CIRCLE", "INTERSECTS-CIRCLE-1000", "INTERSECTS-CIRCLE-10000", "INTERSECTS-CIRCLE-100000", + "INTERSECTS-AZ": if redis { break } @@ -368,6 +372,51 @@ func main() { ) } + switch strings.ToUpper(strings.TrimSpace(test)) { + case "INTERSECTS", "INTERSECTS-AZ": + var mu sync.Mutex + var loaded bool + redbench.Bench("INTERSECTS (intersects-az limit 5)", addr, opts, func(conn net.Conn) bool { + func() { + mu.Lock() + defer mu.Unlock() + if loaded { + return + } + loaded = true + p := make([]byte, 0xFF) + conn.Write([]byte("GET keys:bench:geo az point\r\n")) + n, err := conn.Read(p) + if err != nil { + panic(err) + } + if string(p[:n]) != ":-1\r\n" { + return + } + args := []string{"SET", "key:bench:geo", "az", "object", az.JSON} + out := redcon.AppendArray(nil, len(args)) + for _, arg := range args { + out = redcon.AppendBulkString(out, arg) + } + conn.Write(out) + n, err = conn.Read(p) + if err != nil { + panic(err) + } + if string(p[:n]) != "+OK\r\n" { + panic("expected OK") + } + }() + return prepFn(conn) + }, + func(buf []byte) []byte { + args := []string{"INTERSECTS", "key:bench", "LIMIT", "5", + "COUNT", "GET", "key:bench:geo", "az"} + return redbench.AppendCommand(buf, args...) + }, + ) + } + case "WITHIN", "WITHIN-RECT", "WITHIN-RECT-1000", "WITHIN-RECT-10000", "WITHIN-RECT-100000", "WITHIN-CIRCLE", "WITHIN-CIRCLE-1000", "WITHIN-CIRCLE-10000", "WITHIN-CIRCLE-100000": @@ -544,76 +593,73 @@ func main() { ) } case "EVAL": - if redis { - break - } - var i int64 - getScript := "return tile38.call('GET', KEYS[1], ARGV[1], 'point')" - get4Script := - "local a = tile38.call('GET', KEYS[1], ARGV[1], 'point');" + - "local b = tile38.call('GET', KEYS[1], ARGV[2], 'point');" + - "local c = tile38.call('GET', KEYS[1], ARGV[3], 'point');" + - "local d = tile38.call('GET', KEYS[1], ARGV[4], 'point');" + - "return d" + if !redis { + var i int64 + getScript := "return tile38.call('GET', KEYS[1], ARGV[1], 'point')" + get4Script := + "local a = tile38.call('GET', KEYS[1], ARGV[1], 'point');" + + "local b = tile38.call('GET', KEYS[1], ARGV[2], 'point');" + + "local c = tile38.call('GET', KEYS[1], ARGV[3], 'point');" + + "local d = tile38.call('GET', KEYS[1], ARGV[4], 'point');" + + "return d" - setScript := "return tile38.call('SET', KEYS[1], ARGV[1], 'point', ARGV[2], ARGV[3])" - if !opts.Quiet { - fmt.Println("Scripts to run:") - fmt.Println("GET SCRIPT: " + getScript) - fmt.Println("GET FOUR SCRIPT: " + get4Script) - fmt.Println("SET SCRIPT: " + setScript) + setScript := "return tile38.call('SET', KEYS[1], ARGV[1], 'point', ARGV[2], ARGV[3])" + if !opts.Quiet { + fmt.Println("Scripts to run:") + fmt.Println("GET SCRIPT: " + getScript) + fmt.Println("GET FOUR SCRIPT: " + get4Script) + fmt.Println("SET SCRIPT: " + setScript) + } + + redbench.Bench("EVAL (set point)", addr, opts, prepFn, + func(buf []byte) []byte { + i := atomic.AddInt64(&i, 1) + lat, lon := randPoint() + return redbench.AppendCommand(buf, "EVAL", setScript, "1", + "key:bench", + "id:"+strconv.FormatInt(i, 10), + strconv.FormatFloat(lat, 'f', 5, 64), + strconv.FormatFloat(lon, 'f', 5, 64), + ) + }, + ) + redbench.Bench("EVALNA (set point)", addr, opts, prepFn, + func(buf []byte) []byte { + i := atomic.AddInt64(&i, 1) + lat, lon := randPoint() + return redbench.AppendCommand(buf, "EVALNA", setScript, "1", + "key:bench", + "id:"+strconv.FormatInt(i, 10), + strconv.FormatFloat(lat, 'f', 5, 64), + strconv.FormatFloat(lon, 'f', 5, 64), + ) + }, + ) + redbench.Bench("EVALRO (get point)", addr, opts, prepFn, + func(buf []byte) []byte { + i := atomic.AddInt64(&i, 1) + return redbench.AppendCommand(buf, "EVALRO", getScript, "1", "key:bench", "id:"+strconv.FormatInt(i, 10)) + }, + ) + redbench.Bench("EVALRO (get 4 points)", addr, opts, prepFn, + func(buf []byte) []byte { + i := atomic.AddInt64(&i, 1) + return redbench.AppendCommand(buf, "EVALRO", get4Script, "1", + "key:bench", + "id:"+strconv.FormatInt(i, 10), + "id:"+strconv.FormatInt(i+1, 10), + "id:"+strconv.FormatInt(i+2, 10), + "id:"+strconv.FormatInt(i+3, 10), + ) + }, + ) + redbench.Bench("EVALNA (get point)", addr, opts, prepFn, + func(buf []byte) []byte { + i := atomic.AddInt64(&i, 1) + return redbench.AppendCommand(buf, "EVALNA", getScript, "1", "key:bench", "id:"+strconv.FormatInt(i, 10)) + }, + ) } - redbench.Bench("EVAL (set point)", addr, opts, prepFn, - func(buf []byte) []byte { - i := atomic.AddInt64(&i, 1) - lat, lon := randPoint() - return redbench.AppendCommand(buf, "EVAL", setScript, "1", - "key:bench", - "id:"+strconv.FormatInt(i, 10), - strconv.FormatFloat(lat, 'f', 5, 64), - strconv.FormatFloat(lon, 'f', 5, 64), - ) - }, - ) - redbench.Bench("EVALNA (set point)", addr, opts, prepFn, - func(buf []byte) []byte { - i := atomic.AddInt64(&i, 1) - lat, lon := randPoint() - return redbench.AppendCommand(buf, "EVALNA", setScript, "1", - "key:bench", - "id:"+strconv.FormatInt(i, 10), - strconv.FormatFloat(lat, 'f', 5, 64), - strconv.FormatFloat(lon, 'f', 5, 64), - ) - }, - ) - redbench.Bench("EVALRO (get point)", addr, opts, prepFn, - func(buf []byte) []byte { - i := atomic.AddInt64(&i, 1) - args := []string{"EVALRO", getScript, "1", "key:bench", "id:" + strconv.FormatInt(i, 10)} - return redbench.AppendCommand(buf, args...) - }, - ) - redbench.Bench("EVALRO (get 4 points)", addr, opts, prepFn, - func(buf []byte) []byte { - i := atomic.AddInt64(&i, 1) - args := []string{ - "EVALRO", get4Script, "1", - "key:bench", - "id:" + strconv.FormatInt(i, 10), - "id:" + strconv.FormatInt(i+1, 10), - "id:" + strconv.FormatInt(i+2, 10), - "id:" + strconv.FormatInt(i+3, 10), - } - return redbench.AppendCommand(buf, args...) - }, - ) - redbench.Bench("EVALNA (get point)", addr, opts, prepFn, - func(buf []byte) []byte { - i := atomic.AddInt64(&i, 1) - return redbench.AppendCommand(buf, "EVALNA", getScript, "1", "key:bench", "id:"+strconv.FormatInt(i, 10)) - }, - ) } } } From 7721fb8b8ec5bd0a3e5bcc2936af793a76dae6d0 Mon Sep 17 00:00:00 2001 From: tidwall Date: Sun, 11 Nov 2018 08:30:15 -0700 Subject: [PATCH 14/16] Added substract flag to benchmarks --- cmd/tile38-benchmark/main.go | 32 ++++++++++++++++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) diff --git a/cmd/tile38-benchmark/main.go b/cmd/tile38-benchmark/main.go index 7f613374..19439425 100644 --- a/cmd/tile38-benchmark/main.go +++ b/cmd/tile38-benchmark/main.go @@ -27,7 +27,8 @@ var ( pipeline = 1 csv = false json = false - tests = "PING,SET,GET,INTERSECTS,WITHIN,NEARBY,EVAL" + allTests = "PING,SET,GET,INTERSECTS,WITHIN,NEARBY,EVAL" + tests = allTests redis = false ) @@ -182,7 +183,34 @@ func main() { } opts := fillOpts() addr = fmt.Sprintf("%s:%d", hostname, port) + + testsArr := strings.Split(allTests, ",") + var subtract bool + var add bool for _, test := range strings.Split(tests, ",") { + if strings.HasPrefix(test, "-") { + if add { + os.Stderr.Write([]byte("test flag cannot mix add and subtract\n")) + os.Exit(1) + } + subtract = true + for i := range testsArr { + if strings.ToLower(testsArr[i]) == strings.ToLower(test[1:]) { + testsArr = append(testsArr[:i], testsArr[i+1:]...) + break + } + } + } else if subtract { + add = true + os.Stderr.Write([]byte("test flag cannot mix add and subtract\n")) + os.Exit(1) + } + } + if !subtract { + testsArr = strings.Split(tests, ",") + } + + for _, test := range testsArr { switch strings.ToUpper(strings.TrimSpace(test)) { case "PING": redbench.Bench("PING", addr, opts, prepFn, @@ -390,7 +418,7 @@ func main() { if err != nil { panic(err) } - if string(p[:n]) != ":-1\r\n" { + if string(p[:n]) != "$-1\r\n" { return } args := []string{"SET", "key:bench:geo", "az", "object", az.JSON} From 6616b86eda3496609854c34b26a4c90eb9e5fea8 Mon Sep 17 00:00:00 2001 From: tidwall Date: Sun, 11 Nov 2018 09:29:07 -0700 Subject: [PATCH 15/16] Default numloops to number goprocs --- internal/server/server.go | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/internal/server/server.go b/internal/server/server.go index 520116c5..3ed61699 100644 --- a/internal/server/server.go +++ b/internal/server/server.go @@ -22,7 +22,6 @@ import ( "sync/atomic" "time" - "github.com/klauspost/cpuid" "github.com/tidwall/buntdb" "github.com/tidwall/evio" "github.com/tidwall/geojson" @@ -295,12 +294,7 @@ func (server *Server) isProtected() bool { func (server *Server) evioServe() error { var events evio.Events if core.NumThreads == 0 { - cores := cpuid.CPU.PhysicalCores - if cores == 0 { - events.NumLoops = -1 - } else { - events.NumLoops = cores - } + events.NumLoops = -1 } else { events.NumLoops = core.NumThreads } From 1bdc2135d7d669b2b8b034eb180afa8c4cefb826 Mon Sep 17 00:00:00 2001 From: tidwall Date: Sun, 11 Nov 2018 09:33:58 -0700 Subject: [PATCH 16/16] Update geojson vendor --- Gopkg.lock | 4 +- vendor/github.com/tidwall/geojson/circle.go | 82 ++------------------- 2 files changed, 9 insertions(+), 77 deletions(-) diff --git a/Gopkg.lock b/Gopkg.lock index 6eb3854d..3a60493c 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -243,7 +243,7 @@ [[projects]] branch = "master" - digest = "1:145703130ac1de36086ab350337777161f9c1d791e81a73659ac1f569e15b5e5" + digest = "1:3307384a763736cbcfa625076939fe9a240e5f5c9d6ace507fa4fd1f4f6944d6" name = "github.com/tidwall/geojson" packages = [ ".", @@ -251,7 +251,7 @@ "geometry", ] pruneopts = "" - revision = "dbcb73c57c65ff784ce2ccaad3f062c9787d6f81" + revision = "553da6f08f84f544b5482743fe73c3989facc578" [[projects]] digest = "1:3ddca2bd5496c6922a2a9e636530e178a43c2a534ea6634211acdc7d10222794" diff --git a/vendor/github.com/tidwall/geojson/circle.go b/vendor/github.com/tidwall/geojson/circle.go index 50bac786..fb34e882 100644 --- a/vendor/github.com/tidwall/geojson/circle.go +++ b/vendor/github.com/tidwall/geojson/circle.go @@ -3,7 +3,6 @@ package geojson import ( "math" "strconv" - "sync" "github.com/tidwall/geojson/geo" "github.com/tidwall/geojson/geometry" @@ -212,10 +211,7 @@ func (g *Circle) getObject() Object { return makeCircleObject(g.center, g.meters, g.steps) } -var llmu sync.RWMutex -var llobj Object - -func makeCircleObjectA(center geometry.Point, meters float64, steps int) Object { +func makeCircleObject(center geometry.Point, meters float64, steps int) Object { if meters <= 0 { return NewPoint(center) } @@ -227,9 +223,15 @@ func makeCircleObjectA(center geometry.Point, meters float64, steps int) Object _, maxX := geo.DestinationPoint(center.Y, center.X, meters, 90) minY, _ := geo.DestinationPoint(center.Y, center.X, meters, 180) _, minX := geo.DestinationPoint(center.Y, center.X, meters, 270) + + // TODO: detect of pole and antimeridian crossing and generate a + // valid multigeometry + + // use the half width of the lat and lon lons := (maxX - minX) / 2 lats := (maxY - minY) / 2 + // generate the for th := 0.0; th <= 360.0; th += 360.0 / float64(steps) { radians := (math.Pi / 180) * th x := center.X + lats*math.Cos(radians) @@ -245,73 +247,3 @@ func makeCircleObjectA(center geometry.Point, meters float64, steps int) Object }), ) } -func makeCircleObjectB(center geometry.Point, meters float64, steps int) Object { - if meters <= 0 { - return NewPoint(center) - } - meters = geo.NormalizeDistance(meters) - points := make([]geometry.Point, 0, steps+1) - - step := 360.0 / float64(steps) - i := 0 - for deg := 360.0; deg > 0; deg -= step { - lat, lon := geo.DestinationPoint(center.Y, center.X, meters, deg) - points = append(points, geometry.Point{X: lon, Y: lat}) - i++ - } - // add last connecting point, make a total of steps+1 - points = append(points, points[0]) - - return NewPolygon( - geometry.NewPoly(points, nil, &geometry.IndexOptions{ - Kind: geometry.None, - }), - ) -} - -func makeCircleObject(center geometry.Point, meters float64, steps int) Object { - if meters <= 0 { - return NewPoint(center) - } - - meters = geo.NormalizeDistance(meters) - points := make([]geometry.Point, 0, steps+1) - return makeCircleObjectA(center, meters, steps) - - llmu.RLock() - if llobj != nil { - llmu.RUnlock() - return llobj - } - llmu.RUnlock() - llmu.Lock() - if llobj != nil { - llmu.Unlock() - return llobj - } - defer llmu.Unlock() - - step := 360.0 / float64(steps) - i := 0 - for deg := 360.0; deg > 0; deg -= step { - lat, lon := geo.DestinationPoint(center.Y, center.X, meters, deg) - points = append(points, geometry.Point{X: lon, Y: lat}) - i++ - } - // add last connecting point, make a total of steps+1 - points = append(points, points[0]) - - // for i := 0; i < steps; i++ { - // fmt.Printf("%d: %v\n", i, points[i].X) - // } - - // TODO: account for the pole and antimerdian. In most cases only a - // polygon is needed, but when the circle bounds passes the 90/180 - // lines, we need to create a multipolygon - - llobj = NewPolygon( - geometry.NewPoly(points, nil, geometry.DefaultIndexOptions), - ) - // println(llobj.String()) - return llobj -}