diff --git a/Gopkg.lock b/Gopkg.lock index 78fc8ab8..b49f46e7 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -333,6 +333,14 @@ revision = "48d34adceb39a5bd6ed7c12f38c78cd425436442" version = "v1.0.2" +[[projects]] + branch = "master" + digest = "1:251d31d1270dfc5d995c5ff7ee26dc783a34392b2d692e97e273146d082e25bd" + name = "github.com/tidwall/tinybtree" + packages = ["."] + pruneopts = "" + revision = "de5932d649b50053050d43056146b960f3d90ca5" + [[projects]] branch = "master" digest = "1:9d71091ff8756d88318a4334be685d311b10e1a01c0290ce743187b3bfb1b3f6" @@ -477,6 +485,7 @@ "github.com/tidwall/redcon", "github.com/tidwall/resp", "github.com/tidwall/sjson", + "github.com/tidwall/tinybtree", "github.com/yuin/gopher-lua", "golang.org/x/crypto/ssh/terminal", "golang.org/x/net/context", diff --git a/Gopkg.toml b/Gopkg.toml index 9435396f..cca1c7b3 100644 --- a/Gopkg.toml +++ b/Gopkg.toml @@ -27,6 +27,10 @@ required = [ "github.com/tidwall/evio" ] +[[constraint]] + branch = "master" + name = "github.com/tidwall/tinybtree" + [[constraint]] branch = "master" name = "github.com/tidwall/boxtree" diff --git a/internal/collection/collection.go b/internal/collection/collection.go index d8fe0515..821f0ff4 100644 --- a/internal/collection/collection.go +++ b/internal/collection/collection.go @@ -6,7 +6,7 @@ import ( "github.com/tidwall/geojson" "github.com/tidwall/geojson/geo" "github.com/tidwall/geojson/geometry" - "github.com/tidwall/tile38/internal/ds" + "github.com/tidwall/tinybtree" ) // Cursor allows for quickly paging through Scan, Within, Intersects, and Nearby @@ -35,9 +35,9 @@ func (item *itemT) Less(other btree.Item, ctx interface{}) bool { // Collection represents a collection of geojson objects. type Collection struct { - items ds.BTree // items sorted by keys - index d2.BoxTree // items geospatially indexed - values *btree.BTree // items sorted by value+key + items tinybtree.BTree // items sorted by keys + index d2.BoxTree // items geospatially indexed + values *btree.BTree // items sorted by value+key fieldMap map[string]int fieldValues map[string][]float64 weight int diff --git a/internal/server/crud.go b/internal/server/crud.go index d29dcb03..664a9ed3 100644 --- a/internal/server/crud.go +++ b/internal/server/crud.go @@ -13,8 +13,8 @@ import ( "github.com/tidwall/geojson/geometry" "github.com/tidwall/resp" "github.com/tidwall/tile38/internal/collection" - "github.com/tidwall/tile38/internal/ds" "github.com/tidwall/tile38/internal/glob" + "github.com/tidwall/tinybtree" ) type fvt struct { @@ -520,7 +520,7 @@ func (server *Server) cmdFlushDB(msg *Message) (res resp.Value, d commandDetails err = errInvalidNumberOfArguments return } - server.cols = ds.BTree{} + server.cols = tinybtree.BTree{} server.exlistmu.Lock() server.exlist = nil server.exlistmu.Unlock() diff --git a/internal/server/server.go b/internal/server/server.go index 69471948..192519d7 100644 --- a/internal/server/server.go +++ b/internal/server/server.go @@ -31,10 +31,10 @@ import ( "github.com/tidwall/resp" "github.com/tidwall/tile38/core" "github.com/tidwall/tile38/internal/collection" - "github.com/tidwall/tile38/internal/ds" "github.com/tidwall/tile38/internal/endpoint" "github.com/tidwall/tile38/internal/expire" "github.com/tidwall/tile38/internal/log" + "github.com/tidwall/tinybtree" ) var errOOM = errors.New("OOM command not allowed when used memory > 'maxmemory'") @@ -98,7 +98,7 @@ type Server struct { 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 + cols tinybtree.BTree // data collections expires map[string]map[string]time.Time // synced with cols follows map[*bytes.Buffer]bool @@ -1052,7 +1052,7 @@ func randomKey(n int) string { func (server *Server) reset() { server.aofsz = 0 - server.cols = ds.BTree{} + server.cols = tinybtree.BTree{} server.exlistmu.Lock() server.exlist = nil server.exlistmu.Unlock() diff --git a/vendor/github.com/tidwall/tinybtree/LICENSE b/vendor/github.com/tidwall/tinybtree/LICENSE new file mode 100644 index 00000000..7d54eddd --- /dev/null +++ b/vendor/github.com/tidwall/tinybtree/LICENSE @@ -0,0 +1,20 @@ +The MIT License (MIT) + +Copyright (c) 2017 Joshua J Baker + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/vendor/github.com/tidwall/tinybtree/README.md b/vendor/github.com/tidwall/tinybtree/README.md new file mode 100644 index 00000000..4562d640 --- /dev/null +++ b/vendor/github.com/tidwall/tinybtree/README.md @@ -0,0 +1,44 @@ +# `tinybtree` + +[![GoDoc](https://godoc.org/github.com/tidwall/tinybtree?status.svg)](https://godoc.org/github.com/tidwall/tinybtree) + +Just an itsy bitsy b-tree. + +## Usage + +Keys are strings, values are interfaces. + +### Functions + +``` +Get(key string) (value interface{}, gotten bool) +Set(key string, value interface{}) (prev interface{}, replaced bool) +Delete(key string) (prev interface{}, deleted bool) +Scan(iter func(key string, value interface{}) bool) +Ascend(pivot string, iter func(key string, value interface{}) bool) +Descend(pivot string, iter func(key string, value interface{}) bool) +``` + +### Example + +```go +// Create a btree +var tr tinybtree.BTree + +// Set a key. Returns the previous value and ok a previous value exists. +prev, ok := tr.Set("hello", "world") + +// Get a key. Returns the value and ok if the value exists. +value, ok := tr.Get("hello") + +// Delete a key. Returns the deleted value and ok if the previous value exists. +prev, ok := tr.Delete("hello") +``` + +## Contact + +Josh Baker [@tidwall](http://twitter.com/tidwall) + +## License + +`tinybtree` source code is available under the MIT [License](/LICENSE). diff --git a/internal/ds/btree.go b/vendor/github.com/tidwall/tinybtree/btree.go similarity index 98% rename from internal/ds/btree.go rename to vendor/github.com/tidwall/tinybtree/btree.go index 9a2386ea..91463760 100644 --- a/internal/ds/btree.go +++ b/vendor/github.com/tidwall/tinybtree/btree.go @@ -1,7 +1,7 @@ -package ds +package tinybtree const maxItems = 31 // use an odd number -const minItems = maxItems / 2 +const minItems = maxItems * 40 / 100 type item struct { key string @@ -14,11 +14,6 @@ type node struct { children [maxItems + 1]*node } -type leaf struct { - numItems int - items [maxItems]item -} - // BTree is an ordered set of key/value pairs where the key is a string // and the value is an interface{} type BTree struct { diff --git a/internal/ds/btree_test.go b/vendor/github.com/tidwall/tinybtree/btree_test.go similarity index 81% rename from internal/ds/btree_test.go rename to vendor/github.com/tidwall/tinybtree/btree_test.go index 5f4ad370..c3e6d691 100644 --- a/internal/ds/btree_test.go +++ b/vendor/github.com/tidwall/tinybtree/btree_test.go @@ -1,8 +1,9 @@ -package ds +package tinybtree import ( "fmt" "math/rand" + "sort" "strings" "testing" "time" @@ -408,7 +409,30 @@ func TestBTree(t *testing.T) { } } -func BenchmarkTidwallSet(b *testing.B) { +func BenchmarkTidwallSequentialSet(b *testing.B) { + var tr BTree + keys := randKeys(b.N) + sort.Strings(keys) + b.ResetTimer() + for i := 0; i < b.N; i++ { + tr.Set(keys[i], nil) + } +} + +func BenchmarkTidwallSequentialGet(b *testing.B) { + var tr BTree + keys := randKeys(b.N) + sort.Strings(keys) + for i := 0; i < b.N; i++ { + tr.Set(keys[i], nil) + } + b.ResetTimer() + for i := 0; i < b.N; i++ { + tr.Get(keys[i]) + } +} + +func BenchmarkTidwallRandomSet(b *testing.B) { var tr BTree keys := randKeys(b.N) b.ResetTimer() @@ -417,7 +441,7 @@ func BenchmarkTidwallSet(b *testing.B) { } } -func BenchmarkTidwallGet(b *testing.B) { +func BenchmarkTidwallRandomGet(b *testing.B) { var tr BTree keys := randKeys(b.N) for i := 0; i < b.N; i++ { @@ -429,6 +453,74 @@ func BenchmarkTidwallGet(b *testing.B) { } } +// type googleKind struct { +// key string +// } + +// func (a *googleKind) Less(b btree.Item) bool { +// return a.key < b.(*googleKind).key +// } + +// func BenchmarkGoogleSequentialSet(b *testing.B) { +// tr := btree.New(32) +// keys := randKeys(b.N) +// sort.Strings(keys) +// gkeys := make([]*googleKind, len(keys)) +// for i := 0; i < b.N; i++ { +// gkeys[i] = &googleKind{keys[i]} +// } +// b.ResetTimer() +// for i := 0; i < b.N; i++ { +// tr.ReplaceOrInsert(gkeys[i]) +// } +// } + +// func BenchmarkGoogleSequentialGet(b *testing.B) { +// tr := btree.New(32) +// keys := randKeys(b.N) +// gkeys := make([]*googleKind, len(keys)) +// for i := 0; i < b.N; i++ { +// gkeys[i] = &googleKind{keys[i]} +// } +// for i := 0; i < b.N; i++ { +// tr.ReplaceOrInsert(gkeys[i]) +// } +// sort.Strings(keys) +// b.ResetTimer() +// for i := 0; i < b.N; i++ { +// tr.Get(gkeys[i]) +// } +// } + +// func BenchmarkGoogleRandomSet(b *testing.B) { +// tr := btree.New(32) +// keys := randKeys(b.N) +// gkeys := make([]*googleKind, len(keys)) +// for i := 0; i < b.N; i++ { +// gkeys[i] = &googleKind{keys[i]} +// } +// b.ResetTimer() +// for i := 0; i < b.N; i++ { +// tr.ReplaceOrInsert(gkeys[i]) +// } +// } + +// func BenchmarkGoogleRandomGet(b *testing.B) { +// tr := btree.New(32) +// keys := randKeys(b.N) +// gkeys := make([]*googleKind, len(keys)) +// for i := 0; i < b.N; i++ { +// gkeys[i] = &googleKind{keys[i]} +// } +// for i := 0; i < b.N; i++ { +// tr.ReplaceOrInsert(gkeys[i]) +// } +// b.ResetTimer() +// for i := 0; i < b.N; i++ { +// tr.Get(gkeys[i]) +// } +// } + func TestBTreeOne(t *testing.T) { var tr BTree tr.Set("1", "1")