mirror of https://github.com/tidwall/tile38.git
wip. adding string value type.
This commit is contained in:
parent
bfa204067c
commit
8d89198eaf
|
@ -1,19 +1,38 @@
|
|||
package collection
|
||||
|
||||
import (
|
||||
"github.com/google/btree"
|
||||
"github.com/tidwall/btree"
|
||||
"github.com/tidwall/tile38/geojson"
|
||||
"github.com/tidwall/tile38/index"
|
||||
)
|
||||
|
||||
const (
|
||||
idOrdered = 0
|
||||
valueOrdered = 2
|
||||
)
|
||||
|
||||
type itemT struct {
|
||||
id string
|
||||
object geojson.Object
|
||||
fields []float64
|
||||
}
|
||||
|
||||
func (i *itemT) Less(item btree.Item) bool {
|
||||
func (i *itemT) Less(item btree.Item, ctx int) bool {
|
||||
switch ctx {
|
||||
default:
|
||||
return false
|
||||
case idOrdered:
|
||||
return i.id < item.(*itemT).id
|
||||
case valueOrdered:
|
||||
if i.object.String() < item.(*itemT).object.String() {
|
||||
return true
|
||||
}
|
||||
if i.object.String() > item.(*itemT).object.String() {
|
||||
return false
|
||||
}
|
||||
return i.id < item.(*itemT).id
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func (i *itemT) Rect() (minX, minY, maxX, maxY float64) {
|
||||
|
@ -28,8 +47,9 @@ func (i *itemT) Point() (x, y float64) {
|
|||
|
||||
// Collection represents a collection of geojson objects.
|
||||
type Collection struct {
|
||||
items *btree.BTree
|
||||
index *index.Index
|
||||
items *btree.BTree // items sorted by keys
|
||||
values *btree.BTree // items sorted by value+key
|
||||
index *index.Index // items geospatially indexed
|
||||
fieldMap map[string]int
|
||||
weight int
|
||||
points int
|
||||
|
@ -42,7 +62,8 @@ var counter uint64
|
|||
func New() *Collection {
|
||||
col := &Collection{
|
||||
index: index.New(),
|
||||
items: btree.New(16),
|
||||
items: btree.New(16, idOrdered),
|
||||
values: btree.New(16, valueOrdered),
|
||||
fieldMap: make(map[string]int),
|
||||
}
|
||||
return col
|
||||
|
@ -60,23 +81,7 @@ func (c *Collection) PointCount() int {
|
|||
|
||||
// TotalWeight calculates the in-memory cost of the collection in bytes.
|
||||
func (c *Collection) TotalWeight() int {
|
||||
return c.weight + c.overheadWeight()
|
||||
}
|
||||
|
||||
func (c *Collection) overheadWeight() int {
|
||||
// the field map.
|
||||
mapweight := 0
|
||||
for field := range c.fieldMap {
|
||||
mapweight += len(field) + 8 // key + value
|
||||
}
|
||||
mapweight = int((float64(mapweight) * 1.05) + 28.0) // about an 8% pad plus golang 28 byte map overhead.
|
||||
// the btree. each object takes up 64bits for the interface head for each item.
|
||||
btreeweight := (c.objects * 8)
|
||||
// plus roughly one pointer for every item
|
||||
btreeweight += (c.objects * 8)
|
||||
// also the btree header weight
|
||||
btreeweight += 24
|
||||
return mapweight + btreeweight
|
||||
return c.weight
|
||||
}
|
||||
|
||||
// ReplaceOrInsert adds or replaces an object in the collection and returns the fields array.
|
||||
|
@ -113,7 +118,11 @@ func (c *Collection) remove(id string) (item *itemT, ok bool) {
|
|||
return nil, false
|
||||
}
|
||||
item = i.(*itemT)
|
||||
if item.object.IsGeometry() {
|
||||
c.index.Remove(item)
|
||||
} else {
|
||||
c.values.Delete(item)
|
||||
}
|
||||
c.weight -= len(item.fields) * 8
|
||||
c.weight -= item.object.Weight() + len(item.id)
|
||||
c.points -= item.object.PositionCount()
|
||||
|
@ -123,7 +132,11 @@ func (c *Collection) remove(id string) (item *itemT, ok bool) {
|
|||
|
||||
func (c *Collection) insert(id string, obj geojson.Object) (item *itemT) {
|
||||
item = &itemT{id: id, object: obj}
|
||||
if obj.IsGeometry() {
|
||||
c.index.Insert(item)
|
||||
} else {
|
||||
c.values.ReplaceOrInsert(item)
|
||||
}
|
||||
c.items.ReplaceOrInsert(item)
|
||||
c.weight += obj.Weight() + len(id)
|
||||
c.points += obj.PositionCount()
|
||||
|
|
|
@ -14,7 +14,7 @@ import (
|
|||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/google/btree"
|
||||
"github.com/tidwall/btree"
|
||||
"github.com/tidwall/resp"
|
||||
"github.com/tidwall/tile38/controller/collection"
|
||||
"github.com/tidwall/tile38/controller/log"
|
||||
|
@ -45,7 +45,7 @@ type commandDetailsT struct {
|
|||
timestamp time.Time
|
||||
}
|
||||
|
||||
func (col *collectionT) Less(item btree.Item) bool {
|
||||
func (col *collectionT) Less(item btree.Item, ctx int) bool {
|
||||
return col.Key < item.(*collectionT).Key
|
||||
}
|
||||
|
||||
|
@ -82,7 +82,7 @@ func ListenAndServe(host string, port int, dir string) error {
|
|||
host: host,
|
||||
port: port,
|
||||
dir: dir,
|
||||
cols: btree.New(16),
|
||||
cols: btree.New(16, 0),
|
||||
follows: make(map[*bytes.Buffer]bool),
|
||||
fcond: sync.NewCond(&sync.Mutex{}),
|
||||
lives: make(map[*liveBuffer]bool),
|
||||
|
@ -387,7 +387,7 @@ func randomKey(n int) string {
|
|||
|
||||
func (c *Controller) reset() {
|
||||
c.aofsz = 0
|
||||
c.cols = btree.New(16)
|
||||
c.cols = btree.New(16, 0)
|
||||
}
|
||||
|
||||
func (c *Controller) command(msg *server.Message, w io.Writer) (res string, d commandDetailsT, err error) {
|
||||
|
|
|
@ -7,7 +7,7 @@ import (
|
|||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/google/btree"
|
||||
"github.com/tidwall/btree"
|
||||
"github.com/tidwall/resp"
|
||||
"github.com/tidwall/tile38/controller/collection"
|
||||
"github.com/tidwall/tile38/controller/server"
|
||||
|
@ -92,7 +92,7 @@ func (c *Controller) cmdGet(msg *server.Message) (string, error) {
|
|||
buf.WriteString(`,"object":`)
|
||||
buf.WriteString(o.JSON())
|
||||
} else {
|
||||
vals = append(vals, resp.StringValue(o.JSON()))
|
||||
vals = append(vals, resp.StringValue(o.String()))
|
||||
}
|
||||
} else {
|
||||
switch strings.ToLower(typ) {
|
||||
|
@ -300,7 +300,7 @@ func (c *Controller) cmdFlushDB(msg *server.Message) (res string, d commandDetai
|
|||
err = errInvalidNumberOfArguments
|
||||
return
|
||||
}
|
||||
c.cols = btree.New(16)
|
||||
c.cols = btree.New(16, 0)
|
||||
c.hooks = make(map[string]*Hook)
|
||||
c.hookcols = make(map[string]map[string]*Hook)
|
||||
d.command = "flushdb"
|
||||
|
@ -379,6 +379,13 @@ func (c *Controller) parseSetArgs(vs []resp.Value) (d commandDetailsT, fields []
|
|||
default:
|
||||
err = errInvalidArgument(typ)
|
||||
return
|
||||
case lc(typ, "string"):
|
||||
var str string
|
||||
if vs, str, ok = tokenval(vs); !ok {
|
||||
err = errInvalidNumberOfArguments
|
||||
return
|
||||
}
|
||||
d.obj = geojson.String(str)
|
||||
case lc(typ, "point"):
|
||||
var slat, slon, sz string
|
||||
if vs, slat, ok = tokenval(vs); !ok || slat == "" {
|
||||
|
|
|
@ -5,7 +5,7 @@ import (
|
|||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/google/btree"
|
||||
"github.com/tidwall/btree"
|
||||
"github.com/tidwall/resp"
|
||||
"github.com/tidwall/tile38/controller/server"
|
||||
)
|
||||
|
|
|
@ -325,7 +325,7 @@ func (sw *scanWriter) writeObject(id string, o geojson.Object, fields []float64,
|
|||
} else {
|
||||
switch sw.output {
|
||||
case outputObjects:
|
||||
vals = append(vals, resp.StringValue(o.JSON()))
|
||||
vals = append(vals, resp.StringValue(o.String()))
|
||||
case outputPoints:
|
||||
point := o.CalculatedPoint()
|
||||
if point.Z != 0 {
|
||||
|
|
|
@ -7,7 +7,7 @@ import (
|
|||
"sort"
|
||||
"time"
|
||||
|
||||
"github.com/google/btree"
|
||||
"github.com/tidwall/btree"
|
||||
"github.com/tidwall/resp"
|
||||
"github.com/tidwall/tile38/controller/server"
|
||||
)
|
||||
|
|
|
@ -150,6 +150,11 @@ func (g Feature) JSON() string {
|
|||
return buf.String()
|
||||
}
|
||||
|
||||
// String returns a string representation of the object. This might be JSON or something else.
|
||||
func (g Feature) String() string {
|
||||
return g.JSON()
|
||||
}
|
||||
|
||||
// Bytes is the bytes representation of the object.
|
||||
func (g Feature) Bytes() []byte {
|
||||
var buf bytes.Buffer
|
||||
|
@ -226,3 +231,8 @@ func (g Feature) Nearby(center Position, meters float64) bool {
|
|||
func (g Feature) IsBBoxDefined() bool {
|
||||
return g.BBox != nil
|
||||
}
|
||||
|
||||
// IsGeometry return true if the object is a geojson geometry object. false if it something else.
|
||||
func (g Feature) IsGeometry() bool {
|
||||
return true
|
||||
}
|
||||
|
|
|
@ -126,6 +126,11 @@ func (g FeatureCollection) JSON() string {
|
|||
return buf.String()
|
||||
}
|
||||
|
||||
// String returns a string representation of the object. This might be JSON or something else.
|
||||
func (g FeatureCollection) String() string {
|
||||
return g.JSON()
|
||||
}
|
||||
|
||||
// Bytes is the bytes representation of the object.
|
||||
func (g FeatureCollection) Bytes() []byte {
|
||||
var buf bytes.Buffer
|
||||
|
@ -248,3 +253,8 @@ func (g FeatureCollection) Nearby(center Position, meters float64) bool {
|
|||
func (g FeatureCollection) IsBBoxDefined() bool {
|
||||
return g.BBox != nil
|
||||
}
|
||||
|
||||
// IsGeometry return true if the object is a geojson geometry object. false if it something else.
|
||||
func (g FeatureCollection) IsGeometry() bool {
|
||||
return true
|
||||
}
|
||||
|
|
|
@ -126,6 +126,11 @@ func (g GeometryCollection) JSON() string {
|
|||
return buf.String()
|
||||
}
|
||||
|
||||
// String returns a string representation of the object. This might be JSON or something else.
|
||||
func (g GeometryCollection) String() string {
|
||||
return g.JSON()
|
||||
}
|
||||
|
||||
// Bytes is the bytes representation of the object.
|
||||
func (g GeometryCollection) Bytes() []byte {
|
||||
var buf bytes.Buffer
|
||||
|
@ -248,3 +253,8 @@ func (g GeometryCollection) Nearby(center Position, meters float64) bool {
|
|||
func (g GeometryCollection) IsBBoxDefined() bool {
|
||||
return g.BBox != nil
|
||||
}
|
||||
|
||||
// IsGeometry return true if the object is a geojson geometry object. false if it something else.
|
||||
func (g GeometryCollection) IsGeometry() bool {
|
||||
return true
|
||||
}
|
||||
|
|
|
@ -56,6 +56,11 @@ func (g LineString) JSON() string {
|
|||
return level2JSON("LineString", g.Coordinates, g.BBox)
|
||||
}
|
||||
|
||||
// String returns a string representation of the object. This might be JSON or something else.
|
||||
func (g LineString) String() string {
|
||||
return g.JSON()
|
||||
}
|
||||
|
||||
// Bytes is the bytes representation of the object.
|
||||
func (g LineString) Bytes() []byte {
|
||||
return level2Bytes(lineString, g.Coordinates, g.BBox)
|
||||
|
@ -126,3 +131,8 @@ func (g LineString) Nearby(center Position, meters float64) bool {
|
|||
func (g LineString) IsBBoxDefined() bool {
|
||||
return g.BBox != nil
|
||||
}
|
||||
|
||||
// IsGeometry return true if the object is a geojson geometry object. false if it something else.
|
||||
func (g LineString) IsGeometry() bool {
|
||||
return true
|
||||
}
|
||||
|
|
|
@ -62,6 +62,11 @@ func (g MultiLineString) JSON() string {
|
|||
return level3JSON("MultiLineString", g.Coordinates, g.BBox)
|
||||
}
|
||||
|
||||
// String returns a string representation of the object. This might be JSON or something else.
|
||||
func (g MultiLineString) String() string {
|
||||
return g.JSON()
|
||||
}
|
||||
|
||||
// Bytes is the bytes representation of the object.
|
||||
func (g MultiLineString) Bytes() []byte {
|
||||
return level3Bytes(multiLineString, g.Coordinates, g.BBox)
|
||||
|
@ -184,3 +189,8 @@ func (g MultiLineString) Nearby(center Position, meters float64) bool {
|
|||
func (g MultiLineString) IsBBoxDefined() bool {
|
||||
return g.BBox != nil
|
||||
}
|
||||
|
||||
// IsGeometry return true if the object is a geojson geometry object. false if it something else.
|
||||
func (g MultiLineString) IsGeometry() bool {
|
||||
return true
|
||||
}
|
||||
|
|
|
@ -54,6 +54,11 @@ func (g MultiPoint) JSON() string {
|
|||
return level2JSON("MultiPoint", g.Coordinates, g.BBox)
|
||||
}
|
||||
|
||||
// String returns a string representation of the object. This might be JSON or something else.
|
||||
func (g MultiPoint) String() string {
|
||||
return g.JSON()
|
||||
}
|
||||
|
||||
// Bytes is the bytes representation of the object.
|
||||
func (g MultiPoint) Bytes() []byte {
|
||||
return level2Bytes(multiPoint, g.Coordinates, g.BBox)
|
||||
|
@ -163,3 +168,8 @@ func (g MultiPoint) Nearby(center Position, meters float64) bool {
|
|||
func (g MultiPoint) IsBBoxDefined() bool {
|
||||
return g.BBox != nil
|
||||
}
|
||||
|
||||
// IsGeometry return true if the object is a geojson geometry object. false if it something else.
|
||||
func (g MultiPoint) IsGeometry() bool {
|
||||
return true
|
||||
}
|
||||
|
|
|
@ -66,6 +66,11 @@ func (g MultiPolygon) JSON() string {
|
|||
return level4JSON("MultiPolygon", g.Coordinates, g.BBox)
|
||||
}
|
||||
|
||||
// String returns a string representation of the object. This might be JSON or something else.
|
||||
func (g MultiPolygon) String() string {
|
||||
return g.JSON()
|
||||
}
|
||||
|
||||
// Bytes is the bytes representation of the object.
|
||||
func (g MultiPolygon) Bytes() []byte {
|
||||
return level4Bytes(multiPolygon, g.Coordinates, g.BBox)
|
||||
|
@ -193,3 +198,8 @@ func (g MultiPolygon) Nearby(center Position, meters float64) bool {
|
|||
func (g MultiPolygon) IsBBoxDefined() bool {
|
||||
return g.BBox != nil
|
||||
}
|
||||
|
||||
// IsGeometry return true if the object is a geojson geometry object. false if it something else.
|
||||
func (g MultiPolygon) IsGeometry() bool {
|
||||
return true
|
||||
}
|
||||
|
|
|
@ -76,6 +76,8 @@ type Object interface {
|
|||
CalculatedPoint() Position
|
||||
// JSON is the json representation of the object. This might not be exactly the same as the original.
|
||||
JSON() string
|
||||
// String returns a string represenation of the object. This may be JSON or something else.
|
||||
String() string
|
||||
// Bytes is the bytes representation of the object.
|
||||
Bytes() []byte
|
||||
// PositionCount return the number of coordinates.
|
||||
|
@ -88,6 +90,8 @@ type Object interface {
|
|||
Geohash(precision int) (string, error)
|
||||
// IsBBoxDefined returns true if the object has a defined bbox.
|
||||
IsBBoxDefined() bool
|
||||
// IsGeometry return true if the object is a geojson geometry object. false if it something else.
|
||||
IsGeometry() bool
|
||||
}
|
||||
|
||||
func writeHeader(buf *bytes.Buffer, objType byte, bbox *BBox, isCordZ bool) {
|
||||
|
|
|
@ -55,6 +55,11 @@ func (g Point) JSON() string {
|
|||
return level1JSON("Point", g.Coordinates, g.BBox)
|
||||
}
|
||||
|
||||
// String returns a string representation of the object. This might be JSON or something else.
|
||||
func (g Point) String() string {
|
||||
return g.JSON()
|
||||
}
|
||||
|
||||
// Bytes is the bytes representation of the object.
|
||||
func (g Point) Bytes() []byte {
|
||||
return level1Bytes(point, g.Coordinates, g.BBox)
|
||||
|
@ -135,3 +140,8 @@ func (g Point) Nearby(center Position, meters float64) bool {
|
|||
func (g Point) IsBBoxDefined() bool {
|
||||
return g.BBox != nil
|
||||
}
|
||||
|
||||
// IsGeometry return true if the object is a geojson geometry object. false if it something else.
|
||||
func (g Point) IsGeometry() bool {
|
||||
return true
|
||||
}
|
||||
|
|
|
@ -69,6 +69,11 @@ func (g Polygon) JSON() string {
|
|||
return level3JSON("Polygon", g.Coordinates, g.BBox)
|
||||
}
|
||||
|
||||
// String returns a string representation of the object. This might be JSON or something else.
|
||||
func (g Polygon) String() string {
|
||||
return g.JSON()
|
||||
}
|
||||
|
||||
// Bytes is the bytes representation of the object.
|
||||
func (g Polygon) Bytes() []byte {
|
||||
return level3Bytes(polygon, g.Coordinates, g.BBox)
|
||||
|
@ -202,3 +207,8 @@ func (g Polygon) KML() string {
|
|||
func (g Polygon) IsBBoxDefined() bool {
|
||||
return g.BBox != nil
|
||||
}
|
||||
|
||||
// IsGeometry return true if the object is a geojson geometry object. false if it something else.
|
||||
func (g Polygon) IsGeometry() bool {
|
||||
return true
|
||||
}
|
||||
|
|
|
@ -59,6 +59,11 @@ func (g SimplePoint) JSON() string {
|
|||
return level1JSON("Point", Position{X: g.X, Y: g.Y, Z: 0}, nil)
|
||||
}
|
||||
|
||||
// String returns a string representation of the object. This might be JSON or something else.
|
||||
func (g SimplePoint) String() string {
|
||||
return g.JSON()
|
||||
}
|
||||
|
||||
// Bytes is the bytes representation of the object.
|
||||
func (g SimplePoint) Bytes() []byte {
|
||||
return level1Bytes(point, Position{X: g.X, Y: g.Y, Z: 0}, nil)
|
||||
|
@ -123,3 +128,8 @@ func (g SimplePoint) Nearby(center Position, meters float64) bool {
|
|||
func (g SimplePoint) IsBBoxDefined() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// IsGeometry return true if the object is a geojson geometry object. false if it something else.
|
||||
func (g SimplePoint) IsGeometry() bool {
|
||||
return true
|
||||
}
|
||||
|
|
|
@ -0,0 +1,94 @@
|
|||
package geojson
|
||||
|
||||
import "encoding/json"
|
||||
|
||||
// String is a not a geojson object, but just a string
|
||||
type String string
|
||||
|
||||
func (s String) bboxPtr() *BBox {
|
||||
return nil
|
||||
}
|
||||
func (s String) hasPositions() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// WithinBBox detects if the object is fully contained inside a bbox.
|
||||
func (s String) WithinBBox(bbox BBox) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// IntersectsBBox detects if the object intersects a bbox.
|
||||
func (s String) IntersectsBBox(bbox BBox) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// Within detects if the object is fully contained inside another object.
|
||||
func (s String) Within(o Object) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// Intersects detects if the object intersects another object.
|
||||
func (s String) Intersects(o Object) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// Nearby detects if the object is nearby a position.
|
||||
func (s String) Nearby(center Position, meters float64) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// CalculatedBBox is exterior bbox containing the object.
|
||||
func (s String) CalculatedBBox() BBox {
|
||||
return BBox{}
|
||||
}
|
||||
|
||||
// CalculatedPoint is a point representation of the object.
|
||||
func (s String) CalculatedPoint() Position {
|
||||
return Position{}
|
||||
}
|
||||
|
||||
// JSON is the json representation of the object. This might not be exactly the same as the original.
|
||||
func (s String) JSON() string {
|
||||
b, _ := s.MarshalJSON()
|
||||
return string(b)
|
||||
}
|
||||
|
||||
// String returns a string representation of the object. This might be JSON or something else.
|
||||
func (s String) String() string {
|
||||
return string(s)
|
||||
}
|
||||
|
||||
// IsGeometry return true if the object is a geojson geometry object. false if it something else.
|
||||
func (g String) IsGeometry() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// Bytes is the bytes representation of the object.
|
||||
func (s String) Bytes() []byte {
|
||||
return []byte(s.String())
|
||||
}
|
||||
|
||||
// PositionCount return the number of coordinates.
|
||||
func (s String) PositionCount() int {
|
||||
return 0
|
||||
}
|
||||
|
||||
// Weight returns the in-memory size of the object.
|
||||
func (s String) Weight() int {
|
||||
return len(s)
|
||||
}
|
||||
|
||||
// MarshalJSON allows the object to be encoded in json.Marshal calls.
|
||||
func (s String) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(string(s))
|
||||
}
|
||||
|
||||
// Geohash converts the object to a geohash value.
|
||||
func (s String) Geohash(precision int) (string, error) {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
// IsBBoxDefined returns true if the object has a defined bbox.
|
||||
func (s String) IsBBoxDefined() bool {
|
||||
return false
|
||||
}
|
Loading…
Reference in New Issue