2018-10-29 01:49:45 +03:00
|
|
|
package server
|
2016-03-05 02:08:16 +03:00
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
2016-03-28 18:57:41 +03:00
|
|
|
"sort"
|
2016-03-05 02:08:16 +03:00
|
|
|
"strconv"
|
|
|
|
"strings"
|
|
|
|
"time"
|
|
|
|
|
2018-10-11 00:25:40 +03:00
|
|
|
"github.com/mmcloughlin/geohash"
|
2018-11-24 04:15:14 +03:00
|
|
|
"github.com/tidwall/boxtree/d2"
|
2018-10-11 00:25:40 +03:00
|
|
|
"github.com/tidwall/geojson"
|
|
|
|
"github.com/tidwall/geojson/geometry"
|
2016-03-28 18:57:41 +03:00
|
|
|
"github.com/tidwall/resp"
|
2018-10-11 00:25:40 +03:00
|
|
|
"github.com/tidwall/tile38/internal/collection"
|
2018-10-18 17:12:24 +03:00
|
|
|
"github.com/tidwall/tile38/internal/ds"
|
2018-10-11 00:25:40 +03:00
|
|
|
"github.com/tidwall/tile38/internal/glob"
|
2016-03-05 02:08:16 +03:00
|
|
|
)
|
|
|
|
|
2016-03-28 18:57:41 +03:00
|
|
|
type fvt struct {
|
|
|
|
field string
|
|
|
|
value float64
|
|
|
|
}
|
|
|
|
|
|
|
|
type byField []fvt
|
|
|
|
|
|
|
|
func (a byField) Len() int {
|
|
|
|
return len(a)
|
|
|
|
}
|
|
|
|
func (a byField) Less(i, j int) bool {
|
|
|
|
return a[i].field < a[j].field
|
|
|
|
}
|
|
|
|
func (a byField) Swap(i, j int) {
|
|
|
|
a[i], a[j] = a[j], a[i]
|
|
|
|
}
|
|
|
|
|
|
|
|
func orderFields(fmap map[string]int, fields []float64) []fvt {
|
|
|
|
var fv fvt
|
|
|
|
fvs := make([]fvt, 0, len(fmap))
|
|
|
|
for field, idx := range fmap {
|
|
|
|
if idx < len(fields) {
|
|
|
|
fv.field = field
|
|
|
|
fv.value = fields[idx]
|
2016-03-30 19:32:38 +03:00
|
|
|
if fv.value != 0 {
|
2016-03-28 18:57:41 +03:00
|
|
|
fvs = append(fvs, fv)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
sort.Sort(byField(fvs))
|
|
|
|
return fvs
|
|
|
|
}
|
2018-10-29 01:49:45 +03:00
|
|
|
func (server *Server) cmdBounds(msg *Message) (resp.Value, error) {
|
2016-08-19 18:33:58 +03:00
|
|
|
start := time.Now()
|
2018-10-29 01:49:45 +03:00
|
|
|
vs := msg.Args[1:]
|
2016-08-19 18:33:58 +03:00
|
|
|
|
|
|
|
var ok bool
|
|
|
|
var key string
|
|
|
|
if vs, key, ok = tokenval(vs); !ok || key == "" {
|
2018-10-29 01:49:45 +03:00
|
|
|
return NOMessage, errInvalidNumberOfArguments
|
2016-08-19 18:33:58 +03:00
|
|
|
}
|
|
|
|
if len(vs) != 0 {
|
2018-10-29 01:49:45 +03:00
|
|
|
return NOMessage, errInvalidNumberOfArguments
|
2016-08-19 18:33:58 +03:00
|
|
|
}
|
|
|
|
|
2018-10-29 01:49:45 +03:00
|
|
|
col := server.getCol(key)
|
2016-08-19 18:33:58 +03:00
|
|
|
if col == nil {
|
2018-10-29 01:49:45 +03:00
|
|
|
if msg.OutputType == RESP {
|
Lua scripting feature. (#224)
* Start on lua scripting
* Implement evalsha, script load, script exists, and script flush
* Type conversions from lua to resp/json.
Refactor to make luastate and luascripts persistent in the controller.
* Change controller.command and all underlying commands to return resp.Value.
Serialize only during the ouput.
* First stab at tile38 call from lua
* Change tile38 into tile38.call in Lua
* Property return errors from scripts
* Minor refactoring. No locking on script run
* Cleanup/refactoring
* Create a pool of 5 lua states, allow for more as needed. Refactor.
* Use safe map for scripts. Add a limit for max number of lua states. Refactor.
* Refactor
* Refactor script commands into atomic, read-only, and non-atomic classes.
Proper locking for all three classes.
Add tests for scripts
* More tests for scripts
* Properly escape newlines in lua-produced errors
* Better test for readonly failure
* Correctly convert ok/err messages between lua and resp.
Add pcall, sha1hex, error_reply, status_reply functions to tile38 namespace in lua.
* Add pcall test. Change writeErr to work with string argument
* Make sure eval/evalsha never attempt to write AOF
* Add eval-set and eval-get to benchmarks
* Fix eval benchmark tests, add more
* Improve benchmarks
* Optimizations and refactoring.
* Add lua memtest
* Typo
* Add dependency
* golint fixes
* gofmt fixes
* Add scripting commands to the core/commands.json
* Use ARGV for args inside lua
2017-10-05 18:20:40 +03:00
|
|
|
return resp.NullValue(), nil
|
2016-08-19 18:33:58 +03:00
|
|
|
}
|
2018-10-29 01:49:45 +03:00
|
|
|
return NOMessage, errKeyNotFound
|
2016-08-19 18:33:58 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
vals := make([]resp.Value, 0, 2)
|
|
|
|
var buf bytes.Buffer
|
2018-10-29 01:49:45 +03:00
|
|
|
if msg.OutputType == JSON {
|
2016-08-19 18:33:58 +03:00
|
|
|
buf.WriteString(`{"ok":true`)
|
|
|
|
}
|
2017-08-11 03:32:40 +03:00
|
|
|
minX, minY, maxX, maxY := col.Bounds()
|
2016-10-03 21:37:16 +03:00
|
|
|
|
2018-10-11 00:25:40 +03:00
|
|
|
bbox := geojson.NewRect(geometry.Rect{
|
|
|
|
Min: geometry.Point{X: minX, Y: minY},
|
|
|
|
Max: geometry.Point{X: maxX, Y: maxY},
|
|
|
|
})
|
2018-10-29 01:49:45 +03:00
|
|
|
if msg.OutputType == JSON {
|
2016-08-19 18:33:58 +03:00
|
|
|
buf.WriteString(`,"bounds":`)
|
2018-10-11 00:25:40 +03:00
|
|
|
buf.WriteString(string(bbox.AppendJSON(nil)))
|
2016-08-19 18:33:58 +03:00
|
|
|
} else {
|
|
|
|
vals = append(vals, resp.ArrayValue([]resp.Value{
|
|
|
|
resp.ArrayValue([]resp.Value{
|
2016-10-03 21:37:16 +03:00
|
|
|
resp.FloatValue(minX),
|
|
|
|
resp.FloatValue(minY),
|
2016-08-19 18:33:58 +03:00
|
|
|
}),
|
|
|
|
resp.ArrayValue([]resp.Value{
|
2016-10-03 21:37:16 +03:00
|
|
|
resp.FloatValue(maxX),
|
|
|
|
resp.FloatValue(maxY),
|
2016-08-19 18:33:58 +03:00
|
|
|
}),
|
|
|
|
}))
|
|
|
|
}
|
|
|
|
switch msg.OutputType {
|
2018-10-29 01:49:45 +03:00
|
|
|
case JSON:
|
2016-08-19 18:33:58 +03:00
|
|
|
buf.WriteString(`,"elapsed":"` + time.Now().Sub(start).String() + "\"}")
|
Lua scripting feature. (#224)
* Start on lua scripting
* Implement evalsha, script load, script exists, and script flush
* Type conversions from lua to resp/json.
Refactor to make luastate and luascripts persistent in the controller.
* Change controller.command and all underlying commands to return resp.Value.
Serialize only during the ouput.
* First stab at tile38 call from lua
* Change tile38 into tile38.call in Lua
* Property return errors from scripts
* Minor refactoring. No locking on script run
* Cleanup/refactoring
* Create a pool of 5 lua states, allow for more as needed. Refactor.
* Use safe map for scripts. Add a limit for max number of lua states. Refactor.
* Refactor
* Refactor script commands into atomic, read-only, and non-atomic classes.
Proper locking for all three classes.
Add tests for scripts
* More tests for scripts
* Properly escape newlines in lua-produced errors
* Better test for readonly failure
* Correctly convert ok/err messages between lua and resp.
Add pcall, sha1hex, error_reply, status_reply functions to tile38 namespace in lua.
* Add pcall test. Change writeErr to work with string argument
* Make sure eval/evalsha never attempt to write AOF
* Add eval-set and eval-get to benchmarks
* Fix eval benchmark tests, add more
* Improve benchmarks
* Optimizations and refactoring.
* Add lua memtest
* Typo
* Add dependency
* golint fixes
* gofmt fixes
* Add scripting commands to the core/commands.json
* Use ARGV for args inside lua
2017-10-05 18:20:40 +03:00
|
|
|
return resp.StringValue(buf.String()), nil
|
2018-10-29 01:49:45 +03:00
|
|
|
case RESP:
|
Lua scripting feature. (#224)
* Start on lua scripting
* Implement evalsha, script load, script exists, and script flush
* Type conversions from lua to resp/json.
Refactor to make luastate and luascripts persistent in the controller.
* Change controller.command and all underlying commands to return resp.Value.
Serialize only during the ouput.
* First stab at tile38 call from lua
* Change tile38 into tile38.call in Lua
* Property return errors from scripts
* Minor refactoring. No locking on script run
* Cleanup/refactoring
* Create a pool of 5 lua states, allow for more as needed. Refactor.
* Use safe map for scripts. Add a limit for max number of lua states. Refactor.
* Refactor
* Refactor script commands into atomic, read-only, and non-atomic classes.
Proper locking for all three classes.
Add tests for scripts
* More tests for scripts
* Properly escape newlines in lua-produced errors
* Better test for readonly failure
* Correctly convert ok/err messages between lua and resp.
Add pcall, sha1hex, error_reply, status_reply functions to tile38 namespace in lua.
* Add pcall test. Change writeErr to work with string argument
* Make sure eval/evalsha never attempt to write AOF
* Add eval-set and eval-get to benchmarks
* Fix eval benchmark tests, add more
* Improve benchmarks
* Optimizations and refactoring.
* Add lua memtest
* Typo
* Add dependency
* golint fixes
* gofmt fixes
* Add scripting commands to the core/commands.json
* Use ARGV for args inside lua
2017-10-05 18:20:40 +03:00
|
|
|
return vals[0], nil
|
2016-08-19 18:33:58 +03:00
|
|
|
}
|
2018-10-29 01:49:45 +03:00
|
|
|
return NOMessage, nil
|
2016-08-19 18:33:58 +03:00
|
|
|
}
|
Lua scripting feature. (#224)
* Start on lua scripting
* Implement evalsha, script load, script exists, and script flush
* Type conversions from lua to resp/json.
Refactor to make luastate and luascripts persistent in the controller.
* Change controller.command and all underlying commands to return resp.Value.
Serialize only during the ouput.
* First stab at tile38 call from lua
* Change tile38 into tile38.call in Lua
* Property return errors from scripts
* Minor refactoring. No locking on script run
* Cleanup/refactoring
* Create a pool of 5 lua states, allow for more as needed. Refactor.
* Use safe map for scripts. Add a limit for max number of lua states. Refactor.
* Refactor
* Refactor script commands into atomic, read-only, and non-atomic classes.
Proper locking for all three classes.
Add tests for scripts
* More tests for scripts
* Properly escape newlines in lua-produced errors
* Better test for readonly failure
* Correctly convert ok/err messages between lua and resp.
Add pcall, sha1hex, error_reply, status_reply functions to tile38 namespace in lua.
* Add pcall test. Change writeErr to work with string argument
* Make sure eval/evalsha never attempt to write AOF
* Add eval-set and eval-get to benchmarks
* Fix eval benchmark tests, add more
* Improve benchmarks
* Optimizations and refactoring.
* Add lua memtest
* Typo
* Add dependency
* golint fixes
* gofmt fixes
* Add scripting commands to the core/commands.json
* Use ARGV for args inside lua
2017-10-05 18:20:40 +03:00
|
|
|
|
2018-10-29 01:49:45 +03:00
|
|
|
func (server *Server) cmdType(msg *Message) (resp.Value, error) {
|
2016-08-26 23:42:52 +03:00
|
|
|
start := time.Now()
|
2018-10-29 01:49:45 +03:00
|
|
|
vs := msg.Args[1:]
|
2016-08-26 23:42:52 +03:00
|
|
|
|
|
|
|
var ok bool
|
|
|
|
var key string
|
|
|
|
if vs, key, ok = tokenval(vs); !ok || key == "" {
|
2018-10-29 01:49:45 +03:00
|
|
|
return NOMessage, errInvalidNumberOfArguments
|
2016-08-26 23:42:52 +03:00
|
|
|
}
|
|
|
|
|
2018-10-29 01:49:45 +03:00
|
|
|
col := server.getCol(key)
|
2016-08-26 23:42:52 +03:00
|
|
|
if col == nil {
|
2018-10-29 01:49:45 +03:00
|
|
|
if msg.OutputType == RESP {
|
Lua scripting feature. (#224)
* Start on lua scripting
* Implement evalsha, script load, script exists, and script flush
* Type conversions from lua to resp/json.
Refactor to make luastate and luascripts persistent in the controller.
* Change controller.command and all underlying commands to return resp.Value.
Serialize only during the ouput.
* First stab at tile38 call from lua
* Change tile38 into tile38.call in Lua
* Property return errors from scripts
* Minor refactoring. No locking on script run
* Cleanup/refactoring
* Create a pool of 5 lua states, allow for more as needed. Refactor.
* Use safe map for scripts. Add a limit for max number of lua states. Refactor.
* Refactor
* Refactor script commands into atomic, read-only, and non-atomic classes.
Proper locking for all three classes.
Add tests for scripts
* More tests for scripts
* Properly escape newlines in lua-produced errors
* Better test for readonly failure
* Correctly convert ok/err messages between lua and resp.
Add pcall, sha1hex, error_reply, status_reply functions to tile38 namespace in lua.
* Add pcall test. Change writeErr to work with string argument
* Make sure eval/evalsha never attempt to write AOF
* Add eval-set and eval-get to benchmarks
* Fix eval benchmark tests, add more
* Improve benchmarks
* Optimizations and refactoring.
* Add lua memtest
* Typo
* Add dependency
* golint fixes
* gofmt fixes
* Add scripting commands to the core/commands.json
* Use ARGV for args inside lua
2017-10-05 18:20:40 +03:00
|
|
|
return resp.SimpleStringValue("none"), nil
|
2016-08-26 23:42:52 +03:00
|
|
|
}
|
2018-10-29 01:49:45 +03:00
|
|
|
return NOMessage, errKeyNotFound
|
2016-08-26 23:42:52 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
typ := "hash"
|
|
|
|
|
|
|
|
switch msg.OutputType {
|
2018-10-29 01:49:45 +03:00
|
|
|
case JSON:
|
Lua scripting feature. (#224)
* Start on lua scripting
* Implement evalsha, script load, script exists, and script flush
* Type conversions from lua to resp/json.
Refactor to make luastate and luascripts persistent in the controller.
* Change controller.command and all underlying commands to return resp.Value.
Serialize only during the ouput.
* First stab at tile38 call from lua
* Change tile38 into tile38.call in Lua
* Property return errors from scripts
* Minor refactoring. No locking on script run
* Cleanup/refactoring
* Create a pool of 5 lua states, allow for more as needed. Refactor.
* Use safe map for scripts. Add a limit for max number of lua states. Refactor.
* Refactor
* Refactor script commands into atomic, read-only, and non-atomic classes.
Proper locking for all three classes.
Add tests for scripts
* More tests for scripts
* Properly escape newlines in lua-produced errors
* Better test for readonly failure
* Correctly convert ok/err messages between lua and resp.
Add pcall, sha1hex, error_reply, status_reply functions to tile38 namespace in lua.
* Add pcall test. Change writeErr to work with string argument
* Make sure eval/evalsha never attempt to write AOF
* Add eval-set and eval-get to benchmarks
* Fix eval benchmark tests, add more
* Improve benchmarks
* Optimizations and refactoring.
* Add lua memtest
* Typo
* Add dependency
* golint fixes
* gofmt fixes
* Add scripting commands to the core/commands.json
* Use ARGV for args inside lua
2017-10-05 18:20:40 +03:00
|
|
|
return resp.StringValue(`{"ok":true,"type":` + string(typ) + `,"elapsed":"` + time.Now().Sub(start).String() + "\"}"), nil
|
2018-10-29 01:49:45 +03:00
|
|
|
case RESP:
|
Lua scripting feature. (#224)
* Start on lua scripting
* Implement evalsha, script load, script exists, and script flush
* Type conversions from lua to resp/json.
Refactor to make luastate and luascripts persistent in the controller.
* Change controller.command and all underlying commands to return resp.Value.
Serialize only during the ouput.
* First stab at tile38 call from lua
* Change tile38 into tile38.call in Lua
* Property return errors from scripts
* Minor refactoring. No locking on script run
* Cleanup/refactoring
* Create a pool of 5 lua states, allow for more as needed. Refactor.
* Use safe map for scripts. Add a limit for max number of lua states. Refactor.
* Refactor
* Refactor script commands into atomic, read-only, and non-atomic classes.
Proper locking for all three classes.
Add tests for scripts
* More tests for scripts
* Properly escape newlines in lua-produced errors
* Better test for readonly failure
* Correctly convert ok/err messages between lua and resp.
Add pcall, sha1hex, error_reply, status_reply functions to tile38 namespace in lua.
* Add pcall test. Change writeErr to work with string argument
* Make sure eval/evalsha never attempt to write AOF
* Add eval-set and eval-get to benchmarks
* Fix eval benchmark tests, add more
* Improve benchmarks
* Optimizations and refactoring.
* Add lua memtest
* Typo
* Add dependency
* golint fixes
* gofmt fixes
* Add scripting commands to the core/commands.json
* Use ARGV for args inside lua
2017-10-05 18:20:40 +03:00
|
|
|
return resp.SimpleStringValue(typ), nil
|
2016-08-26 23:42:52 +03:00
|
|
|
}
|
2018-10-29 01:49:45 +03:00
|
|
|
return NOMessage, nil
|
2016-08-26 23:42:52 +03:00
|
|
|
}
|
2016-03-28 18:57:41 +03:00
|
|
|
|
2018-10-29 01:49:45 +03:00
|
|
|
func (server *Server) cmdGet(msg *Message) (resp.Value, error) {
|
2016-03-05 02:08:16 +03:00
|
|
|
start := time.Now()
|
2018-10-29 01:49:45 +03:00
|
|
|
vs := msg.Args[1:]
|
2016-03-28 18:57:41 +03:00
|
|
|
|
|
|
|
var ok bool
|
2016-03-05 02:08:16 +03:00
|
|
|
var key, id, typ, sprecision string
|
2016-03-28 18:57:41 +03:00
|
|
|
if vs, key, ok = tokenval(vs); !ok || key == "" {
|
2018-10-29 01:49:45 +03:00
|
|
|
return NOMessage, errInvalidNumberOfArguments
|
2016-03-05 02:08:16 +03:00
|
|
|
}
|
2016-03-28 18:57:41 +03:00
|
|
|
if vs, id, ok = tokenval(vs); !ok || id == "" {
|
2018-10-29 01:49:45 +03:00
|
|
|
return NOMessage, errInvalidNumberOfArguments
|
2016-03-05 02:08:16 +03:00
|
|
|
}
|
2016-04-01 22:46:39 +03:00
|
|
|
|
|
|
|
withfields := false
|
|
|
|
if _, peek, ok := tokenval(vs); ok && strings.ToLower(peek) == "withfields" {
|
|
|
|
withfields = true
|
|
|
|
vs = vs[1:]
|
|
|
|
}
|
|
|
|
|
2018-10-29 01:49:45 +03:00
|
|
|
col := server.getCol(key)
|
2016-03-05 02:08:16 +03:00
|
|
|
if col == nil {
|
2018-10-29 01:49:45 +03:00
|
|
|
if msg.OutputType == RESP {
|
Lua scripting feature. (#224)
* Start on lua scripting
* Implement evalsha, script load, script exists, and script flush
* Type conversions from lua to resp/json.
Refactor to make luastate and luascripts persistent in the controller.
* Change controller.command and all underlying commands to return resp.Value.
Serialize only during the ouput.
* First stab at tile38 call from lua
* Change tile38 into tile38.call in Lua
* Property return errors from scripts
* Minor refactoring. No locking on script run
* Cleanup/refactoring
* Create a pool of 5 lua states, allow for more as needed. Refactor.
* Use safe map for scripts. Add a limit for max number of lua states. Refactor.
* Refactor
* Refactor script commands into atomic, read-only, and non-atomic classes.
Proper locking for all three classes.
Add tests for scripts
* More tests for scripts
* Properly escape newlines in lua-produced errors
* Better test for readonly failure
* Correctly convert ok/err messages between lua and resp.
Add pcall, sha1hex, error_reply, status_reply functions to tile38 namespace in lua.
* Add pcall test. Change writeErr to work with string argument
* Make sure eval/evalsha never attempt to write AOF
* Add eval-set and eval-get to benchmarks
* Fix eval benchmark tests, add more
* Improve benchmarks
* Optimizations and refactoring.
* Add lua memtest
* Typo
* Add dependency
* golint fixes
* gofmt fixes
* Add scripting commands to the core/commands.json
* Use ARGV for args inside lua
2017-10-05 18:20:40 +03:00
|
|
|
return resp.NullValue(), nil
|
2016-03-28 18:57:41 +03:00
|
|
|
}
|
2018-10-29 01:49:45 +03:00
|
|
|
return NOMessage, errKeyNotFound
|
2016-03-05 02:08:16 +03:00
|
|
|
}
|
|
|
|
o, fields, ok := col.Get(id)
|
2018-10-29 01:49:45 +03:00
|
|
|
ok = ok && !server.hasExpired(key, id)
|
2016-03-05 02:08:16 +03:00
|
|
|
if !ok {
|
2018-10-29 01:49:45 +03:00
|
|
|
if msg.OutputType == RESP {
|
Lua scripting feature. (#224)
* Start on lua scripting
* Implement evalsha, script load, script exists, and script flush
* Type conversions from lua to resp/json.
Refactor to make luastate and luascripts persistent in the controller.
* Change controller.command and all underlying commands to return resp.Value.
Serialize only during the ouput.
* First stab at tile38 call from lua
* Change tile38 into tile38.call in Lua
* Property return errors from scripts
* Minor refactoring. No locking on script run
* Cleanup/refactoring
* Create a pool of 5 lua states, allow for more as needed. Refactor.
* Use safe map for scripts. Add a limit for max number of lua states. Refactor.
* Refactor
* Refactor script commands into atomic, read-only, and non-atomic classes.
Proper locking for all three classes.
Add tests for scripts
* More tests for scripts
* Properly escape newlines in lua-produced errors
* Better test for readonly failure
* Correctly convert ok/err messages between lua and resp.
Add pcall, sha1hex, error_reply, status_reply functions to tile38 namespace in lua.
* Add pcall test. Change writeErr to work with string argument
* Make sure eval/evalsha never attempt to write AOF
* Add eval-set and eval-get to benchmarks
* Fix eval benchmark tests, add more
* Improve benchmarks
* Optimizations and refactoring.
* Add lua memtest
* Typo
* Add dependency
* golint fixes
* gofmt fixes
* Add scripting commands to the core/commands.json
* Use ARGV for args inside lua
2017-10-05 18:20:40 +03:00
|
|
|
return resp.NullValue(), nil
|
2016-03-28 18:57:41 +03:00
|
|
|
}
|
2018-10-29 01:49:45 +03:00
|
|
|
return NOMessage, errIDNotFound
|
2016-03-05 02:08:16 +03:00
|
|
|
}
|
2016-03-28 18:57:41 +03:00
|
|
|
|
|
|
|
vals := make([]resp.Value, 0, 2)
|
2016-03-05 02:08:16 +03:00
|
|
|
var buf bytes.Buffer
|
2018-10-29 01:49:45 +03:00
|
|
|
if msg.OutputType == JSON {
|
2016-03-28 18:57:41 +03:00
|
|
|
buf.WriteString(`{"ok":true`)
|
|
|
|
}
|
2016-07-10 23:23:50 +03:00
|
|
|
vs, typ, ok = tokenval(vs)
|
|
|
|
typ = strings.ToLower(typ)
|
|
|
|
if !ok {
|
|
|
|
typ = "object"
|
|
|
|
}
|
|
|
|
switch typ {
|
|
|
|
default:
|
2018-10-29 01:49:45 +03:00
|
|
|
return NOMessage, errInvalidArgument(typ)
|
2016-07-10 23:23:50 +03:00
|
|
|
case "object":
|
2018-10-29 01:49:45 +03:00
|
|
|
if msg.OutputType == JSON {
|
2016-03-28 18:57:41 +03:00
|
|
|
buf.WriteString(`,"object":`)
|
2018-10-11 00:25:40 +03:00
|
|
|
buf.WriteString(string(o.AppendJSON(nil)))
|
2016-03-28 18:57:41 +03:00
|
|
|
} else {
|
2016-07-10 05:44:28 +03:00
|
|
|
vals = append(vals, resp.StringValue(o.String()))
|
2016-03-28 18:57:41 +03:00
|
|
|
}
|
2016-07-10 23:23:50 +03:00
|
|
|
case "point":
|
2018-10-29 01:49:45 +03:00
|
|
|
if msg.OutputType == JSON {
|
2016-07-10 23:23:50 +03:00
|
|
|
buf.WriteString(`,"point":`)
|
2018-10-11 00:25:40 +03:00
|
|
|
buf.Write(appendJSONSimplePoint(nil, o))
|
2016-07-10 23:23:50 +03:00
|
|
|
} else {
|
2018-10-11 00:25:40 +03:00
|
|
|
point := o.Center()
|
|
|
|
var z float64
|
|
|
|
if gPoint, ok := o.(*geojson.Point); ok {
|
|
|
|
z = gPoint.Z()
|
|
|
|
}
|
|
|
|
if z != 0 {
|
2016-07-10 23:23:50 +03:00
|
|
|
vals = append(vals, resp.ArrayValue([]resp.Value{
|
|
|
|
resp.StringValue(strconv.FormatFloat(point.Y, 'f', -1, 64)),
|
|
|
|
resp.StringValue(strconv.FormatFloat(point.X, 'f', -1, 64)),
|
2018-10-11 00:25:40 +03:00
|
|
|
resp.StringValue(strconv.FormatFloat(z, 'f', -1, 64)),
|
2016-07-10 23:23:50 +03:00
|
|
|
}))
|
2016-03-28 18:57:41 +03:00
|
|
|
} else {
|
|
|
|
vals = append(vals, resp.ArrayValue([]resp.Value{
|
2016-07-10 23:23:50 +03:00
|
|
|
resp.StringValue(strconv.FormatFloat(point.Y, 'f', -1, 64)),
|
|
|
|
resp.StringValue(strconv.FormatFloat(point.X, 'f', -1, 64)),
|
2016-03-28 18:57:41 +03:00
|
|
|
}))
|
|
|
|
}
|
2016-03-05 02:08:16 +03:00
|
|
|
}
|
2016-07-10 23:23:50 +03:00
|
|
|
case "hash":
|
|
|
|
if vs, sprecision, ok = tokenval(vs); !ok || sprecision == "" {
|
2018-10-29 01:49:45 +03:00
|
|
|
return NOMessage, errInvalidNumberOfArguments
|
2016-07-10 23:23:50 +03:00
|
|
|
}
|
2018-10-29 01:49:45 +03:00
|
|
|
if msg.OutputType == JSON {
|
2016-07-10 23:23:50 +03:00
|
|
|
buf.WriteString(`,"hash":`)
|
|
|
|
}
|
|
|
|
precision, err := strconv.ParseInt(sprecision, 10, 64)
|
|
|
|
if err != nil || precision < 1 || precision > 64 {
|
2018-10-29 01:49:45 +03:00
|
|
|
return NOMessage, errInvalidArgument(sprecision)
|
2016-07-10 23:23:50 +03:00
|
|
|
}
|
2018-10-11 00:25:40 +03:00
|
|
|
center := o.Center()
|
|
|
|
p := geohash.EncodeWithPrecision(center.Y, center.X, uint(precision))
|
2018-10-29 01:49:45 +03:00
|
|
|
if msg.OutputType == JSON {
|
2016-07-10 23:23:50 +03:00
|
|
|
buf.WriteString(`"` + p + `"`)
|
|
|
|
} else {
|
|
|
|
vals = append(vals, resp.StringValue(p))
|
|
|
|
}
|
|
|
|
case "bounds":
|
2018-10-29 01:49:45 +03:00
|
|
|
if msg.OutputType == JSON {
|
2016-07-10 23:23:50 +03:00
|
|
|
buf.WriteString(`,"bounds":`)
|
2018-10-11 00:25:40 +03:00
|
|
|
buf.Write(appendJSONSimpleBounds(nil, o))
|
2016-07-10 23:23:50 +03:00
|
|
|
} else {
|
2018-10-11 00:25:40 +03:00
|
|
|
bbox := o.Rect()
|
2016-07-10 23:23:50 +03:00
|
|
|
vals = append(vals, resp.ArrayValue([]resp.Value{
|
|
|
|
resp.ArrayValue([]resp.Value{
|
|
|
|
resp.FloatValue(bbox.Min.Y),
|
|
|
|
resp.FloatValue(bbox.Min.X),
|
|
|
|
}),
|
|
|
|
resp.ArrayValue([]resp.Value{
|
|
|
|
resp.FloatValue(bbox.Max.Y),
|
|
|
|
resp.FloatValue(bbox.Max.X),
|
|
|
|
}),
|
|
|
|
}))
|
|
|
|
}
|
2016-03-05 02:08:16 +03:00
|
|
|
}
|
2016-07-10 23:23:50 +03:00
|
|
|
|
2016-03-28 18:57:41 +03:00
|
|
|
if len(vs) != 0 {
|
2018-10-29 01:49:45 +03:00
|
|
|
return NOMessage, errInvalidNumberOfArguments
|
2016-03-05 02:08:16 +03:00
|
|
|
}
|
2016-04-01 22:46:39 +03:00
|
|
|
if withfields {
|
|
|
|
fvs := orderFields(col.FieldMap(), fields)
|
|
|
|
if len(fvs) > 0 {
|
|
|
|
fvals := make([]resp.Value, 0, len(fvs)*2)
|
2018-10-29 01:49:45 +03:00
|
|
|
if msg.OutputType == JSON {
|
2016-04-01 22:46:39 +03:00
|
|
|
buf.WriteString(`,"fields":{`)
|
|
|
|
}
|
|
|
|
for i, fv := range fvs {
|
2018-10-29 01:49:45 +03:00
|
|
|
if msg.OutputType == JSON {
|
2016-04-01 22:46:39 +03:00
|
|
|
if i > 0 {
|
|
|
|
buf.WriteString(`,`)
|
|
|
|
}
|
|
|
|
buf.WriteString(jsonString(fv.field) + ":" + strconv.FormatFloat(fv.value, 'f', -1, 64))
|
|
|
|
} else {
|
|
|
|
fvals = append(fvals, resp.StringValue(fv.field), resp.StringValue(strconv.FormatFloat(fv.value, 'f', -1, 64)))
|
2016-03-05 02:08:16 +03:00
|
|
|
}
|
2016-04-01 22:46:39 +03:00
|
|
|
i++
|
|
|
|
}
|
2018-10-29 01:49:45 +03:00
|
|
|
if msg.OutputType == JSON {
|
2016-04-01 22:46:39 +03:00
|
|
|
buf.WriteString(`}`)
|
2016-03-28 18:57:41 +03:00
|
|
|
} else {
|
2016-04-01 22:46:39 +03:00
|
|
|
vals = append(vals, resp.ArrayValue(fvals))
|
2016-03-05 02:08:16 +03:00
|
|
|
}
|
2016-03-28 18:57:41 +03:00
|
|
|
}
|
|
|
|
}
|
2016-04-01 22:46:39 +03:00
|
|
|
switch msg.OutputType {
|
2018-10-29 01:49:45 +03:00
|
|
|
case JSON:
|
2016-03-28 18:57:41 +03:00
|
|
|
buf.WriteString(`,"elapsed":"` + time.Now().Sub(start).String() + "\"}")
|
Lua scripting feature. (#224)
* Start on lua scripting
* Implement evalsha, script load, script exists, and script flush
* Type conversions from lua to resp/json.
Refactor to make luastate and luascripts persistent in the controller.
* Change controller.command and all underlying commands to return resp.Value.
Serialize only during the ouput.
* First stab at tile38 call from lua
* Change tile38 into tile38.call in Lua
* Property return errors from scripts
* Minor refactoring. No locking on script run
* Cleanup/refactoring
* Create a pool of 5 lua states, allow for more as needed. Refactor.
* Use safe map for scripts. Add a limit for max number of lua states. Refactor.
* Refactor
* Refactor script commands into atomic, read-only, and non-atomic classes.
Proper locking for all three classes.
Add tests for scripts
* More tests for scripts
* Properly escape newlines in lua-produced errors
* Better test for readonly failure
* Correctly convert ok/err messages between lua and resp.
Add pcall, sha1hex, error_reply, status_reply functions to tile38 namespace in lua.
* Add pcall test. Change writeErr to work with string argument
* Make sure eval/evalsha never attempt to write AOF
* Add eval-set and eval-get to benchmarks
* Fix eval benchmark tests, add more
* Improve benchmarks
* Optimizations and refactoring.
* Add lua memtest
* Typo
* Add dependency
* golint fixes
* gofmt fixes
* Add scripting commands to the core/commands.json
* Use ARGV for args inside lua
2017-10-05 18:20:40 +03:00
|
|
|
return resp.StringValue(buf.String()), nil
|
2018-10-29 01:49:45 +03:00
|
|
|
case RESP:
|
2016-04-01 22:46:39 +03:00
|
|
|
var oval resp.Value
|
|
|
|
if withfields {
|
|
|
|
oval = resp.ArrayValue(vals)
|
|
|
|
} else {
|
|
|
|
oval = vals[0]
|
|
|
|
}
|
Lua scripting feature. (#224)
* Start on lua scripting
* Implement evalsha, script load, script exists, and script flush
* Type conversions from lua to resp/json.
Refactor to make luastate and luascripts persistent in the controller.
* Change controller.command and all underlying commands to return resp.Value.
Serialize only during the ouput.
* First stab at tile38 call from lua
* Change tile38 into tile38.call in Lua
* Property return errors from scripts
* Minor refactoring. No locking on script run
* Cleanup/refactoring
* Create a pool of 5 lua states, allow for more as needed. Refactor.
* Use safe map for scripts. Add a limit for max number of lua states. Refactor.
* Refactor
* Refactor script commands into atomic, read-only, and non-atomic classes.
Proper locking for all three classes.
Add tests for scripts
* More tests for scripts
* Properly escape newlines in lua-produced errors
* Better test for readonly failure
* Correctly convert ok/err messages between lua and resp.
Add pcall, sha1hex, error_reply, status_reply functions to tile38 namespace in lua.
* Add pcall test. Change writeErr to work with string argument
* Make sure eval/evalsha never attempt to write AOF
* Add eval-set and eval-get to benchmarks
* Fix eval benchmark tests, add more
* Improve benchmarks
* Optimizations and refactoring.
* Add lua memtest
* Typo
* Add dependency
* golint fixes
* gofmt fixes
* Add scripting commands to the core/commands.json
* Use ARGV for args inside lua
2017-10-05 18:20:40 +03:00
|
|
|
return oval, nil
|
2016-03-05 02:08:16 +03:00
|
|
|
}
|
2018-10-29 01:49:45 +03:00
|
|
|
return NOMessage, nil
|
2016-03-05 02:08:16 +03:00
|
|
|
}
|
|
|
|
|
2018-11-24 01:53:33 +03:00
|
|
|
func (server *Server) cmdDel(msg *Message) (res resp.Value, d commandDetails, err error) {
|
2016-03-28 18:57:41 +03:00
|
|
|
start := time.Now()
|
2018-10-29 01:49:45 +03:00
|
|
|
vs := msg.Args[1:]
|
2016-03-28 18:57:41 +03:00
|
|
|
var ok bool
|
|
|
|
if vs, d.key, ok = tokenval(vs); !ok || d.key == "" {
|
2016-03-05 02:08:16 +03:00
|
|
|
err = errInvalidNumberOfArguments
|
|
|
|
return
|
|
|
|
}
|
2016-03-28 18:57:41 +03:00
|
|
|
if vs, d.id, ok = tokenval(vs); !ok || d.id == "" {
|
2016-03-05 02:08:16 +03:00
|
|
|
err = errInvalidNumberOfArguments
|
|
|
|
return
|
|
|
|
}
|
2016-03-28 18:57:41 +03:00
|
|
|
if len(vs) != 0 {
|
2016-03-05 02:08:16 +03:00
|
|
|
err = errInvalidNumberOfArguments
|
|
|
|
return
|
|
|
|
}
|
2016-03-28 18:57:41 +03:00
|
|
|
found := false
|
2018-10-29 01:49:45 +03:00
|
|
|
col := server.getCol(d.key)
|
2016-03-05 02:08:16 +03:00
|
|
|
if col != nil {
|
2018-08-16 23:07:55 +03:00
|
|
|
d.obj, d.fields, ok = col.Delete(d.id)
|
2016-03-28 18:57:41 +03:00
|
|
|
if ok {
|
2016-07-13 07:59:36 +03:00
|
|
|
if col.Count() == 0 {
|
2018-10-29 01:49:45 +03:00
|
|
|
server.deleteCol(d.key)
|
2016-03-28 18:57:41 +03:00
|
|
|
}
|
|
|
|
found = true
|
2016-03-05 02:08:16 +03:00
|
|
|
}
|
|
|
|
}
|
2018-10-29 01:49:45 +03:00
|
|
|
server.clearIDExpires(d.key, d.id)
|
2016-03-05 02:08:16 +03:00
|
|
|
d.command = "del"
|
2016-03-28 18:57:41 +03:00
|
|
|
d.updated = found
|
2016-04-02 17:20:30 +03:00
|
|
|
d.timestamp = time.Now()
|
2016-03-28 18:57:41 +03:00
|
|
|
switch msg.OutputType {
|
2018-10-29 01:49:45 +03:00
|
|
|
case JSON:
|
Lua scripting feature. (#224)
* Start on lua scripting
* Implement evalsha, script load, script exists, and script flush
* Type conversions from lua to resp/json.
Refactor to make luastate and luascripts persistent in the controller.
* Change controller.command and all underlying commands to return resp.Value.
Serialize only during the ouput.
* First stab at tile38 call from lua
* Change tile38 into tile38.call in Lua
* Property return errors from scripts
* Minor refactoring. No locking on script run
* Cleanup/refactoring
* Create a pool of 5 lua states, allow for more as needed. Refactor.
* Use safe map for scripts. Add a limit for max number of lua states. Refactor.
* Refactor
* Refactor script commands into atomic, read-only, and non-atomic classes.
Proper locking for all three classes.
Add tests for scripts
* More tests for scripts
* Properly escape newlines in lua-produced errors
* Better test for readonly failure
* Correctly convert ok/err messages between lua and resp.
Add pcall, sha1hex, error_reply, status_reply functions to tile38 namespace in lua.
* Add pcall test. Change writeErr to work with string argument
* Make sure eval/evalsha never attempt to write AOF
* Add eval-set and eval-get to benchmarks
* Fix eval benchmark tests, add more
* Improve benchmarks
* Optimizations and refactoring.
* Add lua memtest
* Typo
* Add dependency
* golint fixes
* gofmt fixes
* Add scripting commands to the core/commands.json
* Use ARGV for args inside lua
2017-10-05 18:20:40 +03:00
|
|
|
res = resp.StringValue(`{"ok":true,"elapsed":"` + time.Now().Sub(start).String() + "\"}")
|
2018-10-29 01:49:45 +03:00
|
|
|
case RESP:
|
2016-03-28 18:57:41 +03:00
|
|
|
if d.updated {
|
Lua scripting feature. (#224)
* Start on lua scripting
* Implement evalsha, script load, script exists, and script flush
* Type conversions from lua to resp/json.
Refactor to make luastate and luascripts persistent in the controller.
* Change controller.command and all underlying commands to return resp.Value.
Serialize only during the ouput.
* First stab at tile38 call from lua
* Change tile38 into tile38.call in Lua
* Property return errors from scripts
* Minor refactoring. No locking on script run
* Cleanup/refactoring
* Create a pool of 5 lua states, allow for more as needed. Refactor.
* Use safe map for scripts. Add a limit for max number of lua states. Refactor.
* Refactor
* Refactor script commands into atomic, read-only, and non-atomic classes.
Proper locking for all three classes.
Add tests for scripts
* More tests for scripts
* Properly escape newlines in lua-produced errors
* Better test for readonly failure
* Correctly convert ok/err messages between lua and resp.
Add pcall, sha1hex, error_reply, status_reply functions to tile38 namespace in lua.
* Add pcall test. Change writeErr to work with string argument
* Make sure eval/evalsha never attempt to write AOF
* Add eval-set and eval-get to benchmarks
* Fix eval benchmark tests, add more
* Improve benchmarks
* Optimizations and refactoring.
* Add lua memtest
* Typo
* Add dependency
* golint fixes
* gofmt fixes
* Add scripting commands to the core/commands.json
* Use ARGV for args inside lua
2017-10-05 18:20:40 +03:00
|
|
|
res = resp.IntegerValue(1)
|
2016-03-28 18:57:41 +03:00
|
|
|
} else {
|
Lua scripting feature. (#224)
* Start on lua scripting
* Implement evalsha, script load, script exists, and script flush
* Type conversions from lua to resp/json.
Refactor to make luastate and luascripts persistent in the controller.
* Change controller.command and all underlying commands to return resp.Value.
Serialize only during the ouput.
* First stab at tile38 call from lua
* Change tile38 into tile38.call in Lua
* Property return errors from scripts
* Minor refactoring. No locking on script run
* Cleanup/refactoring
* Create a pool of 5 lua states, allow for more as needed. Refactor.
* Use safe map for scripts. Add a limit for max number of lua states. Refactor.
* Refactor
* Refactor script commands into atomic, read-only, and non-atomic classes.
Proper locking for all three classes.
Add tests for scripts
* More tests for scripts
* Properly escape newlines in lua-produced errors
* Better test for readonly failure
* Correctly convert ok/err messages between lua and resp.
Add pcall, sha1hex, error_reply, status_reply functions to tile38 namespace in lua.
* Add pcall test. Change writeErr to work with string argument
* Make sure eval/evalsha never attempt to write AOF
* Add eval-set and eval-get to benchmarks
* Fix eval benchmark tests, add more
* Improve benchmarks
* Optimizations and refactoring.
* Add lua memtest
* Typo
* Add dependency
* golint fixes
* gofmt fixes
* Add scripting commands to the core/commands.json
* Use ARGV for args inside lua
2017-10-05 18:20:40 +03:00
|
|
|
res = resp.IntegerValue(0)
|
2016-03-28 18:57:41 +03:00
|
|
|
}
|
|
|
|
}
|
2016-03-05 02:08:16 +03:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2018-11-24 01:53:33 +03:00
|
|
|
func (server *Server) cmdPdel(msg *Message) (res resp.Value, d commandDetails, err error) {
|
2016-12-29 17:53:01 +03:00
|
|
|
start := time.Now()
|
2018-10-29 01:49:45 +03:00
|
|
|
vs := msg.Args[1:]
|
2016-12-29 17:53:01 +03:00
|
|
|
var ok bool
|
|
|
|
if vs, d.key, ok = tokenval(vs); !ok || d.key == "" {
|
|
|
|
err = errInvalidNumberOfArguments
|
|
|
|
return
|
|
|
|
}
|
|
|
|
if vs, d.pattern, ok = tokenval(vs); !ok || d.pattern == "" {
|
|
|
|
err = errInvalidNumberOfArguments
|
|
|
|
return
|
|
|
|
}
|
|
|
|
if len(vs) != 0 {
|
|
|
|
err = errInvalidNumberOfArguments
|
|
|
|
return
|
|
|
|
}
|
|
|
|
now := time.Now()
|
|
|
|
iter := func(id string, o geojson.Object, fields []float64) bool {
|
|
|
|
if match, _ := glob.Match(d.pattern, id); match {
|
2018-11-24 01:53:33 +03:00
|
|
|
d.children = append(d.children, &commandDetails{
|
2016-12-29 17:53:01 +03:00
|
|
|
command: "del",
|
|
|
|
updated: true,
|
|
|
|
timestamp: now,
|
|
|
|
key: d.key,
|
|
|
|
id: id,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
2017-03-29 22:50:04 +03:00
|
|
|
var expired int
|
2018-10-29 01:49:45 +03:00
|
|
|
col := server.getCol(d.key)
|
2016-12-29 17:53:01 +03:00
|
|
|
if col != nil {
|
|
|
|
g := glob.Parse(d.pattern, false)
|
|
|
|
if g.Limits[0] == "" && g.Limits[1] == "" {
|
2018-11-02 16:09:56 +03:00
|
|
|
col.Scan(false, nil, iter)
|
2016-12-29 17:53:01 +03:00
|
|
|
} else {
|
2018-11-02 16:09:56 +03:00
|
|
|
col.ScanRange(g.Limits[0], g.Limits[1], false, nil, iter)
|
2016-12-29 17:53:01 +03:00
|
|
|
}
|
|
|
|
var atLeastOneNotDeleted bool
|
|
|
|
for i, dc := range d.children {
|
2018-08-16 23:07:55 +03:00
|
|
|
dc.obj, dc.fields, ok = col.Delete(dc.id)
|
2016-12-29 17:53:01 +03:00
|
|
|
if !ok {
|
|
|
|
d.children[i].command = "?"
|
|
|
|
atLeastOneNotDeleted = true
|
|
|
|
} else {
|
|
|
|
d.children[i] = dc
|
|
|
|
}
|
2018-10-29 01:49:45 +03:00
|
|
|
server.clearIDExpires(d.key, dc.id)
|
2016-12-29 17:53:01 +03:00
|
|
|
}
|
|
|
|
if atLeastOneNotDeleted {
|
2018-11-24 01:53:33 +03:00
|
|
|
var nchildren []*commandDetails
|
2016-12-29 17:53:01 +03:00
|
|
|
for _, dc := range d.children {
|
|
|
|
if dc.command == "del" {
|
|
|
|
nchildren = append(nchildren, dc)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
d.children = nchildren
|
|
|
|
}
|
|
|
|
if col.Count() == 0 {
|
2018-10-29 01:49:45 +03:00
|
|
|
server.deleteCol(d.key)
|
2016-12-29 17:53:01 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
d.command = "pdel"
|
|
|
|
d.updated = len(d.children) > 0
|
|
|
|
d.timestamp = now
|
|
|
|
d.parent = true
|
|
|
|
switch msg.OutputType {
|
2018-10-29 01:49:45 +03:00
|
|
|
case JSON:
|
Lua scripting feature. (#224)
* Start on lua scripting
* Implement evalsha, script load, script exists, and script flush
* Type conversions from lua to resp/json.
Refactor to make luastate and luascripts persistent in the controller.
* Change controller.command and all underlying commands to return resp.Value.
Serialize only during the ouput.
* First stab at tile38 call from lua
* Change tile38 into tile38.call in Lua
* Property return errors from scripts
* Minor refactoring. No locking on script run
* Cleanup/refactoring
* Create a pool of 5 lua states, allow for more as needed. Refactor.
* Use safe map for scripts. Add a limit for max number of lua states. Refactor.
* Refactor
* Refactor script commands into atomic, read-only, and non-atomic classes.
Proper locking for all three classes.
Add tests for scripts
* More tests for scripts
* Properly escape newlines in lua-produced errors
* Better test for readonly failure
* Correctly convert ok/err messages between lua and resp.
Add pcall, sha1hex, error_reply, status_reply functions to tile38 namespace in lua.
* Add pcall test. Change writeErr to work with string argument
* Make sure eval/evalsha never attempt to write AOF
* Add eval-set and eval-get to benchmarks
* Fix eval benchmark tests, add more
* Improve benchmarks
* Optimizations and refactoring.
* Add lua memtest
* Typo
* Add dependency
* golint fixes
* gofmt fixes
* Add scripting commands to the core/commands.json
* Use ARGV for args inside lua
2017-10-05 18:20:40 +03:00
|
|
|
res = resp.StringValue(`{"ok":true,"elapsed":"` + time.Now().Sub(start).String() + "\"}")
|
2018-10-29 01:49:45 +03:00
|
|
|
case RESP:
|
2017-03-29 22:50:04 +03:00
|
|
|
total := len(d.children) - expired
|
|
|
|
if total < 0 {
|
|
|
|
total = 0
|
|
|
|
}
|
Lua scripting feature. (#224)
* Start on lua scripting
* Implement evalsha, script load, script exists, and script flush
* Type conversions from lua to resp/json.
Refactor to make luastate and luascripts persistent in the controller.
* Change controller.command and all underlying commands to return resp.Value.
Serialize only during the ouput.
* First stab at tile38 call from lua
* Change tile38 into tile38.call in Lua
* Property return errors from scripts
* Minor refactoring. No locking on script run
* Cleanup/refactoring
* Create a pool of 5 lua states, allow for more as needed. Refactor.
* Use safe map for scripts. Add a limit for max number of lua states. Refactor.
* Refactor
* Refactor script commands into atomic, read-only, and non-atomic classes.
Proper locking for all three classes.
Add tests for scripts
* More tests for scripts
* Properly escape newlines in lua-produced errors
* Better test for readonly failure
* Correctly convert ok/err messages between lua and resp.
Add pcall, sha1hex, error_reply, status_reply functions to tile38 namespace in lua.
* Add pcall test. Change writeErr to work with string argument
* Make sure eval/evalsha never attempt to write AOF
* Add eval-set and eval-get to benchmarks
* Fix eval benchmark tests, add more
* Improve benchmarks
* Optimizations and refactoring.
* Add lua memtest
* Typo
* Add dependency
* golint fixes
* gofmt fixes
* Add scripting commands to the core/commands.json
* Use ARGV for args inside lua
2017-10-05 18:20:40 +03:00
|
|
|
res = resp.IntegerValue(total)
|
2016-12-29 17:53:01 +03:00
|
|
|
}
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2018-11-24 01:53:33 +03:00
|
|
|
func (server *Server) cmdDrop(msg *Message) (res resp.Value, d commandDetails, err error) {
|
2016-03-28 18:57:41 +03:00
|
|
|
start := time.Now()
|
2018-10-29 01:49:45 +03:00
|
|
|
vs := msg.Args[1:]
|
2016-03-28 18:57:41 +03:00
|
|
|
var ok bool
|
|
|
|
if vs, d.key, ok = tokenval(vs); !ok || d.key == "" {
|
2016-03-05 02:08:16 +03:00
|
|
|
err = errInvalidNumberOfArguments
|
|
|
|
return
|
|
|
|
}
|
2016-03-28 18:57:41 +03:00
|
|
|
if len(vs) != 0 {
|
2016-03-05 02:08:16 +03:00
|
|
|
err = errInvalidNumberOfArguments
|
|
|
|
return
|
|
|
|
}
|
2018-10-29 01:49:45 +03:00
|
|
|
col := server.getCol(d.key)
|
2016-03-05 02:08:16 +03:00
|
|
|
if col != nil {
|
2018-10-29 01:49:45 +03:00
|
|
|
server.deleteCol(d.key)
|
2016-03-28 18:57:41 +03:00
|
|
|
d.updated = true
|
2016-03-05 02:08:16 +03:00
|
|
|
} else {
|
|
|
|
d.key = "" // ignore the details
|
2016-03-28 18:57:41 +03:00
|
|
|
d.updated = false
|
2016-03-05 02:08:16 +03:00
|
|
|
}
|
|
|
|
d.command = "drop"
|
2016-04-02 17:20:30 +03:00
|
|
|
d.timestamp = time.Now()
|
2018-10-29 01:49:45 +03:00
|
|
|
server.clearKeyExpires(d.key)
|
2016-03-28 18:57:41 +03:00
|
|
|
switch msg.OutputType {
|
2018-10-29 01:49:45 +03:00
|
|
|
case JSON:
|
Lua scripting feature. (#224)
* Start on lua scripting
* Implement evalsha, script load, script exists, and script flush
* Type conversions from lua to resp/json.
Refactor to make luastate and luascripts persistent in the controller.
* Change controller.command and all underlying commands to return resp.Value.
Serialize only during the ouput.
* First stab at tile38 call from lua
* Change tile38 into tile38.call in Lua
* Property return errors from scripts
* Minor refactoring. No locking on script run
* Cleanup/refactoring
* Create a pool of 5 lua states, allow for more as needed. Refactor.
* Use safe map for scripts. Add a limit for max number of lua states. Refactor.
* Refactor
* Refactor script commands into atomic, read-only, and non-atomic classes.
Proper locking for all three classes.
Add tests for scripts
* More tests for scripts
* Properly escape newlines in lua-produced errors
* Better test for readonly failure
* Correctly convert ok/err messages between lua and resp.
Add pcall, sha1hex, error_reply, status_reply functions to tile38 namespace in lua.
* Add pcall test. Change writeErr to work with string argument
* Make sure eval/evalsha never attempt to write AOF
* Add eval-set and eval-get to benchmarks
* Fix eval benchmark tests, add more
* Improve benchmarks
* Optimizations and refactoring.
* Add lua memtest
* Typo
* Add dependency
* golint fixes
* gofmt fixes
* Add scripting commands to the core/commands.json
* Use ARGV for args inside lua
2017-10-05 18:20:40 +03:00
|
|
|
res = resp.StringValue(`{"ok":true,"elapsed":"` + time.Now().Sub(start).String() + "\"}")
|
2018-10-29 01:49:45 +03:00
|
|
|
case RESP:
|
2016-03-28 18:57:41 +03:00
|
|
|
if d.updated {
|
Lua scripting feature. (#224)
* Start on lua scripting
* Implement evalsha, script load, script exists, and script flush
* Type conversions from lua to resp/json.
Refactor to make luastate and luascripts persistent in the controller.
* Change controller.command and all underlying commands to return resp.Value.
Serialize only during the ouput.
* First stab at tile38 call from lua
* Change tile38 into tile38.call in Lua
* Property return errors from scripts
* Minor refactoring. No locking on script run
* Cleanup/refactoring
* Create a pool of 5 lua states, allow for more as needed. Refactor.
* Use safe map for scripts. Add a limit for max number of lua states. Refactor.
* Refactor
* Refactor script commands into atomic, read-only, and non-atomic classes.
Proper locking for all three classes.
Add tests for scripts
* More tests for scripts
* Properly escape newlines in lua-produced errors
* Better test for readonly failure
* Correctly convert ok/err messages between lua and resp.
Add pcall, sha1hex, error_reply, status_reply functions to tile38 namespace in lua.
* Add pcall test. Change writeErr to work with string argument
* Make sure eval/evalsha never attempt to write AOF
* Add eval-set and eval-get to benchmarks
* Fix eval benchmark tests, add more
* Improve benchmarks
* Optimizations and refactoring.
* Add lua memtest
* Typo
* Add dependency
* golint fixes
* gofmt fixes
* Add scripting commands to the core/commands.json
* Use ARGV for args inside lua
2017-10-05 18:20:40 +03:00
|
|
|
res = resp.IntegerValue(1)
|
2016-03-28 18:57:41 +03:00
|
|
|
} else {
|
Lua scripting feature. (#224)
* Start on lua scripting
* Implement evalsha, script load, script exists, and script flush
* Type conversions from lua to resp/json.
Refactor to make luastate and luascripts persistent in the controller.
* Change controller.command and all underlying commands to return resp.Value.
Serialize only during the ouput.
* First stab at tile38 call from lua
* Change tile38 into tile38.call in Lua
* Property return errors from scripts
* Minor refactoring. No locking on script run
* Cleanup/refactoring
* Create a pool of 5 lua states, allow for more as needed. Refactor.
* Use safe map for scripts. Add a limit for max number of lua states. Refactor.
* Refactor
* Refactor script commands into atomic, read-only, and non-atomic classes.
Proper locking for all three classes.
Add tests for scripts
* More tests for scripts
* Properly escape newlines in lua-produced errors
* Better test for readonly failure
* Correctly convert ok/err messages between lua and resp.
Add pcall, sha1hex, error_reply, status_reply functions to tile38 namespace in lua.
* Add pcall test. Change writeErr to work with string argument
* Make sure eval/evalsha never attempt to write AOF
* Add eval-set and eval-get to benchmarks
* Fix eval benchmark tests, add more
* Improve benchmarks
* Optimizations and refactoring.
* Add lua memtest
* Typo
* Add dependency
* golint fixes
* gofmt fixes
* Add scripting commands to the core/commands.json
* Use ARGV for args inside lua
2017-10-05 18:20:40 +03:00
|
|
|
res = resp.IntegerValue(0)
|
2016-03-28 18:57:41 +03:00
|
|
|
}
|
|
|
|
}
|
2016-03-05 02:08:16 +03:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2018-11-24 01:53:33 +03:00
|
|
|
func (server *Server) cmdFlushDB(msg *Message) (res resp.Value, d commandDetails, err error) {
|
2016-03-28 18:57:41 +03:00
|
|
|
start := time.Now()
|
2018-10-29 01:49:45 +03:00
|
|
|
vs := msg.Args[1:]
|
2016-03-28 18:57:41 +03:00
|
|
|
if len(vs) != 0 {
|
2016-03-05 02:08:16 +03:00
|
|
|
err = errInvalidNumberOfArguments
|
|
|
|
return
|
|
|
|
}
|
2018-10-29 01:49:45 +03:00
|
|
|
server.cols = ds.BTree{}
|
|
|
|
server.exlistmu.Lock()
|
|
|
|
server.exlist = nil
|
|
|
|
server.exlistmu.Unlock()
|
|
|
|
server.expires = make(map[string]map[string]time.Time)
|
|
|
|
server.hooks = make(map[string]*Hook)
|
2018-11-24 04:15:14 +03:00
|
|
|
server.hooksOut = make(map[string]*Hook)
|
|
|
|
server.hookTree = d2.BoxTree{}
|
2016-03-05 02:08:16 +03:00
|
|
|
d.command = "flushdb"
|
2016-03-28 18:57:41 +03:00
|
|
|
d.updated = true
|
2016-04-02 17:20:30 +03:00
|
|
|
d.timestamp = time.Now()
|
2016-03-28 18:57:41 +03:00
|
|
|
switch msg.OutputType {
|
2018-10-29 01:49:45 +03:00
|
|
|
case JSON:
|
Lua scripting feature. (#224)
* Start on lua scripting
* Implement evalsha, script load, script exists, and script flush
* Type conversions from lua to resp/json.
Refactor to make luastate and luascripts persistent in the controller.
* Change controller.command and all underlying commands to return resp.Value.
Serialize only during the ouput.
* First stab at tile38 call from lua
* Change tile38 into tile38.call in Lua
* Property return errors from scripts
* Minor refactoring. No locking on script run
* Cleanup/refactoring
* Create a pool of 5 lua states, allow for more as needed. Refactor.
* Use safe map for scripts. Add a limit for max number of lua states. Refactor.
* Refactor
* Refactor script commands into atomic, read-only, and non-atomic classes.
Proper locking for all three classes.
Add tests for scripts
* More tests for scripts
* Properly escape newlines in lua-produced errors
* Better test for readonly failure
* Correctly convert ok/err messages between lua and resp.
Add pcall, sha1hex, error_reply, status_reply functions to tile38 namespace in lua.
* Add pcall test. Change writeErr to work with string argument
* Make sure eval/evalsha never attempt to write AOF
* Add eval-set and eval-get to benchmarks
* Fix eval benchmark tests, add more
* Improve benchmarks
* Optimizations and refactoring.
* Add lua memtest
* Typo
* Add dependency
* golint fixes
* gofmt fixes
* Add scripting commands to the core/commands.json
* Use ARGV for args inside lua
2017-10-05 18:20:40 +03:00
|
|
|
res = resp.StringValue(`{"ok":true,"elapsed":"` + time.Now().Sub(start).String() + "\"}")
|
2018-10-29 01:49:45 +03:00
|
|
|
case RESP:
|
Lua scripting feature. (#224)
* Start on lua scripting
* Implement evalsha, script load, script exists, and script flush
* Type conversions from lua to resp/json.
Refactor to make luastate and luascripts persistent in the controller.
* Change controller.command and all underlying commands to return resp.Value.
Serialize only during the ouput.
* First stab at tile38 call from lua
* Change tile38 into tile38.call in Lua
* Property return errors from scripts
* Minor refactoring. No locking on script run
* Cleanup/refactoring
* Create a pool of 5 lua states, allow for more as needed. Refactor.
* Use safe map for scripts. Add a limit for max number of lua states. Refactor.
* Refactor
* Refactor script commands into atomic, read-only, and non-atomic classes.
Proper locking for all three classes.
Add tests for scripts
* More tests for scripts
* Properly escape newlines in lua-produced errors
* Better test for readonly failure
* Correctly convert ok/err messages between lua and resp.
Add pcall, sha1hex, error_reply, status_reply functions to tile38 namespace in lua.
* Add pcall test. Change writeErr to work with string argument
* Make sure eval/evalsha never attempt to write AOF
* Add eval-set and eval-get to benchmarks
* Fix eval benchmark tests, add more
* Improve benchmarks
* Optimizations and refactoring.
* Add lua memtest
* Typo
* Add dependency
* golint fixes
* gofmt fixes
* Add scripting commands to the core/commands.json
* Use ARGV for args inside lua
2017-10-05 18:20:40 +03:00
|
|
|
res = resp.SimpleStringValue("OK")
|
2016-03-28 18:57:41 +03:00
|
|
|
}
|
2016-03-05 02:08:16 +03:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2018-10-29 01:49:45 +03:00
|
|
|
func (server *Server) parseSetArgs(vs []string) (
|
2018-11-24 01:53:33 +03:00
|
|
|
d commandDetails, fields []string, values []float64,
|
2016-10-03 18:31:13 +03:00
|
|
|
xx, nx bool,
|
2018-10-29 01:49:45 +03:00
|
|
|
expires *float64, etype []byte, evs []string, err error,
|
2016-07-15 22:22:48 +03:00
|
|
|
) {
|
2016-03-28 18:57:41 +03:00
|
|
|
var ok bool
|
2016-11-09 23:43:26 +03:00
|
|
|
var typ []byte
|
2016-03-28 18:57:41 +03:00
|
|
|
if vs, d.key, ok = tokenval(vs); !ok || d.key == "" {
|
2016-03-05 02:08:16 +03:00
|
|
|
err = errInvalidNumberOfArguments
|
|
|
|
return
|
|
|
|
}
|
2016-03-28 18:57:41 +03:00
|
|
|
if vs, d.id, ok = tokenval(vs); !ok || d.id == "" {
|
2016-03-05 02:08:16 +03:00
|
|
|
err = errInvalidNumberOfArguments
|
|
|
|
return
|
|
|
|
}
|
2016-11-09 23:43:26 +03:00
|
|
|
var arg []byte
|
2018-10-29 01:49:45 +03:00
|
|
|
var nvs []string
|
2016-03-05 02:08:16 +03:00
|
|
|
for {
|
2016-11-09 23:43:26 +03:00
|
|
|
if nvs, arg, ok = tokenvalbytes(vs); !ok || len(arg) == 0 {
|
2016-03-05 02:08:16 +03:00
|
|
|
err = errInvalidNumberOfArguments
|
|
|
|
return
|
|
|
|
}
|
2016-11-09 23:43:26 +03:00
|
|
|
if lcb(arg, "field") {
|
2016-03-28 18:57:41 +03:00
|
|
|
vs = nvs
|
2016-03-05 02:08:16 +03:00
|
|
|
var name string
|
|
|
|
var svalue string
|
|
|
|
var value float64
|
2016-03-28 18:57:41 +03:00
|
|
|
if vs, name, ok = tokenval(vs); !ok || name == "" {
|
2016-03-05 02:08:16 +03:00
|
|
|
err = errInvalidNumberOfArguments
|
|
|
|
return
|
|
|
|
}
|
|
|
|
if isReservedFieldName(name) {
|
|
|
|
err = errInvalidArgument(name)
|
|
|
|
return
|
|
|
|
}
|
2016-03-28 18:57:41 +03:00
|
|
|
if vs, svalue, ok = tokenval(vs); !ok || svalue == "" {
|
2016-03-05 02:08:16 +03:00
|
|
|
err = errInvalidNumberOfArguments
|
|
|
|
return
|
|
|
|
}
|
|
|
|
value, err = strconv.ParseFloat(svalue, 64)
|
|
|
|
if err != nil {
|
|
|
|
err = errInvalidArgument(svalue)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
fields = append(fields, name)
|
|
|
|
values = append(values, value)
|
|
|
|
continue
|
|
|
|
}
|
2016-11-09 23:43:26 +03:00
|
|
|
if lcb(arg, "ex") {
|
2016-07-15 22:22:48 +03:00
|
|
|
vs = nvs
|
|
|
|
if expires != nil {
|
2016-11-09 23:43:26 +03:00
|
|
|
err = errInvalidArgument(string(arg))
|
2016-07-15 22:22:48 +03:00
|
|
|
return
|
|
|
|
}
|
|
|
|
var s string
|
|
|
|
var v float64
|
|
|
|
if vs, s, ok = tokenval(vs); !ok || s == "" {
|
|
|
|
err = errInvalidNumberOfArguments
|
|
|
|
return
|
|
|
|
}
|
|
|
|
v, err = strconv.ParseFloat(s, 64)
|
|
|
|
if err != nil {
|
|
|
|
err = errInvalidArgument(s)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
expires = &v
|
|
|
|
continue
|
|
|
|
}
|
2016-11-09 23:43:26 +03:00
|
|
|
if lcb(arg, "xx") {
|
2016-10-03 18:31:13 +03:00
|
|
|
vs = nvs
|
|
|
|
if nx {
|
2016-11-09 23:43:26 +03:00
|
|
|
err = errInvalidArgument(string(arg))
|
2016-10-03 18:31:13 +03:00
|
|
|
return
|
|
|
|
}
|
|
|
|
xx = true
|
|
|
|
continue
|
|
|
|
}
|
2016-11-09 23:43:26 +03:00
|
|
|
if lcb(arg, "nx") {
|
2016-10-03 18:31:13 +03:00
|
|
|
vs = nvs
|
|
|
|
if xx {
|
2016-11-09 23:43:26 +03:00
|
|
|
err = errInvalidArgument(string(arg))
|
2016-10-03 18:31:13 +03:00
|
|
|
return
|
|
|
|
}
|
|
|
|
nx = true
|
|
|
|
continue
|
|
|
|
}
|
2016-03-05 02:08:16 +03:00
|
|
|
break
|
|
|
|
}
|
2016-11-09 23:43:26 +03:00
|
|
|
if vs, typ, ok = tokenvalbytes(vs); !ok || len(typ) == 0 {
|
2016-03-05 02:08:16 +03:00
|
|
|
err = errInvalidNumberOfArguments
|
|
|
|
return
|
|
|
|
}
|
2016-03-28 18:57:41 +03:00
|
|
|
if len(vs) == 0 {
|
2016-03-05 02:08:16 +03:00
|
|
|
err = errInvalidNumberOfArguments
|
|
|
|
return
|
|
|
|
}
|
|
|
|
etype = typ
|
2016-03-28 18:57:41 +03:00
|
|
|
evs = vs
|
2016-03-05 02:08:16 +03:00
|
|
|
switch {
|
|
|
|
default:
|
2016-11-09 23:43:26 +03:00
|
|
|
err = errInvalidArgument(string(typ))
|
2016-03-05 02:08:16 +03:00
|
|
|
return
|
2016-11-09 23:43:26 +03:00
|
|
|
case lcb(typ, "string"):
|
2016-07-10 05:44:28 +03:00
|
|
|
var str string
|
|
|
|
if vs, str, ok = tokenval(vs); !ok {
|
|
|
|
err = errInvalidNumberOfArguments
|
|
|
|
return
|
|
|
|
}
|
2018-10-11 00:25:40 +03:00
|
|
|
d.obj = collection.String(str)
|
2016-11-09 23:43:26 +03:00
|
|
|
case lcb(typ, "point"):
|
2016-03-05 02:08:16 +03:00
|
|
|
var slat, slon, sz string
|
2016-03-28 18:57:41 +03:00
|
|
|
if vs, slat, ok = tokenval(vs); !ok || slat == "" {
|
2016-03-05 02:08:16 +03:00
|
|
|
err = errInvalidNumberOfArguments
|
|
|
|
return
|
|
|
|
}
|
2016-03-28 18:57:41 +03:00
|
|
|
if vs, slon, ok = tokenval(vs); !ok || slon == "" {
|
2016-03-05 02:08:16 +03:00
|
|
|
err = errInvalidNumberOfArguments
|
|
|
|
return
|
|
|
|
}
|
2016-03-28 18:57:41 +03:00
|
|
|
vs, sz, ok = tokenval(vs)
|
|
|
|
if !ok || sz == "" {
|
2018-10-11 00:25:40 +03:00
|
|
|
var x, y float64
|
|
|
|
y, err = strconv.ParseFloat(slat, 64)
|
2016-03-05 02:08:16 +03:00
|
|
|
if err != nil {
|
|
|
|
err = errInvalidArgument(slat)
|
|
|
|
return
|
|
|
|
}
|
2018-10-11 00:25:40 +03:00
|
|
|
x, err = strconv.ParseFloat(slon, 64)
|
2016-03-05 02:08:16 +03:00
|
|
|
if err != nil {
|
|
|
|
err = errInvalidArgument(slon)
|
|
|
|
return
|
|
|
|
}
|
2018-10-11 00:25:40 +03:00
|
|
|
d.obj = geojson.NewPoint(geometry.Point{X: x, Y: y})
|
2016-03-05 02:08:16 +03:00
|
|
|
} else {
|
2018-10-11 00:25:40 +03:00
|
|
|
var x, y, z float64
|
|
|
|
y, err = strconv.ParseFloat(slat, 64)
|
2016-03-05 02:08:16 +03:00
|
|
|
if err != nil {
|
|
|
|
err = errInvalidArgument(slat)
|
|
|
|
return
|
|
|
|
}
|
2018-10-11 00:25:40 +03:00
|
|
|
x, err = strconv.ParseFloat(slon, 64)
|
2016-03-05 02:08:16 +03:00
|
|
|
if err != nil {
|
|
|
|
err = errInvalidArgument(slon)
|
|
|
|
return
|
|
|
|
}
|
2018-10-11 00:25:40 +03:00
|
|
|
z, err = strconv.ParseFloat(sz, 64)
|
2016-03-05 02:08:16 +03:00
|
|
|
if err != nil {
|
|
|
|
err = errInvalidArgument(sz)
|
|
|
|
return
|
|
|
|
}
|
2018-10-11 00:25:40 +03:00
|
|
|
d.obj = geojson.NewPointZ(geometry.Point{X: x, Y: y}, z)
|
2016-03-05 02:08:16 +03:00
|
|
|
}
|
2016-11-09 23:43:26 +03:00
|
|
|
case lcb(typ, "bounds"):
|
2016-03-05 02:08:16 +03:00
|
|
|
var sminlat, sminlon, smaxlat, smaxlon string
|
2016-03-28 18:57:41 +03:00
|
|
|
if vs, sminlat, ok = tokenval(vs); !ok || sminlat == "" {
|
2016-03-05 02:08:16 +03:00
|
|
|
err = errInvalidNumberOfArguments
|
|
|
|
return
|
|
|
|
}
|
2016-03-28 18:57:41 +03:00
|
|
|
if vs, sminlon, ok = tokenval(vs); !ok || sminlon == "" {
|
2016-03-05 02:08:16 +03:00
|
|
|
err = errInvalidNumberOfArguments
|
|
|
|
return
|
|
|
|
}
|
2016-03-28 18:57:41 +03:00
|
|
|
if vs, smaxlat, ok = tokenval(vs); !ok || smaxlat == "" {
|
2016-03-05 02:08:16 +03:00
|
|
|
err = errInvalidNumberOfArguments
|
|
|
|
return
|
|
|
|
}
|
2016-03-28 18:57:41 +03:00
|
|
|
if vs, smaxlon, ok = tokenval(vs); !ok || smaxlon == "" {
|
2016-03-05 02:08:16 +03:00
|
|
|
err = errInvalidNumberOfArguments
|
|
|
|
return
|
|
|
|
}
|
|
|
|
var minlat, minlon, maxlat, maxlon float64
|
|
|
|
minlat, err = strconv.ParseFloat(sminlat, 64)
|
|
|
|
if err != nil {
|
|
|
|
err = errInvalidArgument(sminlat)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
minlon, err = strconv.ParseFloat(sminlon, 64)
|
|
|
|
if err != nil {
|
|
|
|
err = errInvalidArgument(sminlon)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
maxlat, err = strconv.ParseFloat(smaxlat, 64)
|
|
|
|
if err != nil {
|
|
|
|
err = errInvalidArgument(smaxlat)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
maxlon, err = strconv.ParseFloat(smaxlon, 64)
|
|
|
|
if err != nil {
|
|
|
|
err = errInvalidArgument(smaxlon)
|
|
|
|
return
|
|
|
|
}
|
2018-10-11 00:25:40 +03:00
|
|
|
d.obj = geojson.NewRect(geometry.Rect{
|
|
|
|
Min: geometry.Point{X: minlon, Y: minlat},
|
|
|
|
Max: geometry.Point{X: maxlon, Y: maxlat},
|
|
|
|
})
|
2016-11-09 23:43:26 +03:00
|
|
|
case lcb(typ, "hash"):
|
2016-03-05 02:08:16 +03:00
|
|
|
var shash string
|
2016-03-28 18:57:41 +03:00
|
|
|
if vs, shash, ok = tokenval(vs); !ok || shash == "" {
|
2016-03-05 02:08:16 +03:00
|
|
|
err = errInvalidNumberOfArguments
|
|
|
|
return
|
|
|
|
}
|
2018-10-11 00:25:40 +03:00
|
|
|
lat, lon := geohash.Decode(shash)
|
|
|
|
d.obj = geojson.NewPoint(geometry.Point{X: lon, Y: lat})
|
2016-11-09 23:43:26 +03:00
|
|
|
case lcb(typ, "object"):
|
2016-03-28 18:57:41 +03:00
|
|
|
var object string
|
|
|
|
if vs, object, ok = tokenval(vs); !ok || object == "" {
|
|
|
|
err = errInvalidNumberOfArguments
|
|
|
|
return
|
|
|
|
}
|
2018-10-29 01:49:45 +03:00
|
|
|
d.obj, err = geojson.Parse(object, &server.geomParseOpts)
|
2016-03-05 02:08:16 +03:00
|
|
|
if err != nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
2016-03-28 18:57:41 +03:00
|
|
|
if len(vs) != 0 {
|
|
|
|
err = errInvalidNumberOfArguments
|
|
|
|
}
|
2016-03-05 02:08:16 +03:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2018-11-24 01:53:33 +03:00
|
|
|
func (server *Server) cmdSet(msg *Message) (res resp.Value, d commandDetails, err error) {
|
2018-10-29 01:49:45 +03:00
|
|
|
if server.config.maxMemory() > 0 && server.outOfMemory.on() {
|
2016-05-24 05:44:25 +03:00
|
|
|
err = errOOM
|
|
|
|
return
|
|
|
|
}
|
2016-03-28 18:57:41 +03:00
|
|
|
start := time.Now()
|
2018-10-29 01:49:45 +03:00
|
|
|
vs := msg.Args[1:]
|
2016-10-03 18:31:13 +03:00
|
|
|
var fmap map[string]int
|
2016-03-05 02:08:16 +03:00
|
|
|
var fields []string
|
|
|
|
var values []float64
|
2016-10-03 18:31:13 +03:00
|
|
|
var xx, nx bool
|
2016-07-15 22:22:48 +03:00
|
|
|
var ex *float64
|
2018-10-29 01:49:45 +03:00
|
|
|
d, fields, values, xx, nx, ex, _, _, err = server.parseSetArgs(vs)
|
2016-03-05 02:08:16 +03:00
|
|
|
if err != nil {
|
|
|
|
return
|
|
|
|
}
|
2018-10-29 01:49:45 +03:00
|
|
|
col := server.getCol(d.key)
|
2016-03-05 02:08:16 +03:00
|
|
|
if col == nil {
|
2016-10-03 18:31:13 +03:00
|
|
|
if xx {
|
|
|
|
goto notok
|
|
|
|
}
|
2016-03-05 02:08:16 +03:00
|
|
|
col = collection.New()
|
2018-10-29 01:49:45 +03:00
|
|
|
server.setCol(d.key, col)
|
2016-03-05 02:08:16 +03:00
|
|
|
}
|
2016-10-31 20:17:30 +03:00
|
|
|
if xx || nx {
|
2016-10-03 18:31:13 +03:00
|
|
|
_, _, ok := col.Get(d.id)
|
2016-10-31 20:17:30 +03:00
|
|
|
if (nx && ok) || (xx && !ok) {
|
2016-10-03 18:31:13 +03:00
|
|
|
goto notok
|
|
|
|
}
|
|
|
|
}
|
2018-10-29 01:49:45 +03:00
|
|
|
server.clearIDExpires(d.key, d.id)
|
2018-08-16 23:07:55 +03:00
|
|
|
d.oldObj, d.oldFields, d.fields = col.Set(d.id, d.obj, fields, values)
|
2016-03-05 02:08:16 +03:00
|
|
|
d.command = "set"
|
2016-03-28 18:57:41 +03:00
|
|
|
d.updated = true // perhaps we should do a diff on the previous object?
|
2016-04-02 17:20:30 +03:00
|
|
|
d.timestamp = time.Now()
|
2018-10-29 01:49:45 +03:00
|
|
|
if msg.ConnType != Null || msg.OutputType != Null {
|
2016-12-06 02:24:26 +03:00
|
|
|
// likely loaded from aof at server startup, ignore field remapping.
|
|
|
|
fmap = col.FieldMap()
|
|
|
|
d.fmap = make(map[string]int)
|
|
|
|
for key, idx := range fmap {
|
|
|
|
d.fmap[key] = idx
|
|
|
|
}
|
|
|
|
}
|
2016-07-15 22:22:48 +03:00
|
|
|
if ex != nil {
|
2018-10-29 01:49:45 +03:00
|
|
|
server.expireAt(d.key, d.id, d.timestamp.Add(time.Duration(float64(time.Second)*(*ex))))
|
2016-07-15 22:22:48 +03:00
|
|
|
}
|
2016-03-28 18:57:41 +03:00
|
|
|
switch msg.OutputType {
|
2016-11-09 23:43:26 +03:00
|
|
|
default:
|
2018-10-29 01:49:45 +03:00
|
|
|
case JSON:
|
Lua scripting feature. (#224)
* Start on lua scripting
* Implement evalsha, script load, script exists, and script flush
* Type conversions from lua to resp/json.
Refactor to make luastate and luascripts persistent in the controller.
* Change controller.command and all underlying commands to return resp.Value.
Serialize only during the ouput.
* First stab at tile38 call from lua
* Change tile38 into tile38.call in Lua
* Property return errors from scripts
* Minor refactoring. No locking on script run
* Cleanup/refactoring
* Create a pool of 5 lua states, allow for more as needed. Refactor.
* Use safe map for scripts. Add a limit for max number of lua states. Refactor.
* Refactor
* Refactor script commands into atomic, read-only, and non-atomic classes.
Proper locking for all three classes.
Add tests for scripts
* More tests for scripts
* Properly escape newlines in lua-produced errors
* Better test for readonly failure
* Correctly convert ok/err messages between lua and resp.
Add pcall, sha1hex, error_reply, status_reply functions to tile38 namespace in lua.
* Add pcall test. Change writeErr to work with string argument
* Make sure eval/evalsha never attempt to write AOF
* Add eval-set and eval-get to benchmarks
* Fix eval benchmark tests, add more
* Improve benchmarks
* Optimizations and refactoring.
* Add lua memtest
* Typo
* Add dependency
* golint fixes
* gofmt fixes
* Add scripting commands to the core/commands.json
* Use ARGV for args inside lua
2017-10-05 18:20:40 +03:00
|
|
|
res = resp.StringValue(`{"ok":true,"elapsed":"` + time.Now().Sub(start).String() + "\"}")
|
2018-10-29 01:49:45 +03:00
|
|
|
case RESP:
|
Lua scripting feature. (#224)
* Start on lua scripting
* Implement evalsha, script load, script exists, and script flush
* Type conversions from lua to resp/json.
Refactor to make luastate and luascripts persistent in the controller.
* Change controller.command and all underlying commands to return resp.Value.
Serialize only during the ouput.
* First stab at tile38 call from lua
* Change tile38 into tile38.call in Lua
* Property return errors from scripts
* Minor refactoring. No locking on script run
* Cleanup/refactoring
* Create a pool of 5 lua states, allow for more as needed. Refactor.
* Use safe map for scripts. Add a limit for max number of lua states. Refactor.
* Refactor
* Refactor script commands into atomic, read-only, and non-atomic classes.
Proper locking for all three classes.
Add tests for scripts
* More tests for scripts
* Properly escape newlines in lua-produced errors
* Better test for readonly failure
* Correctly convert ok/err messages between lua and resp.
Add pcall, sha1hex, error_reply, status_reply functions to tile38 namespace in lua.
* Add pcall test. Change writeErr to work with string argument
* Make sure eval/evalsha never attempt to write AOF
* Add eval-set and eval-get to benchmarks
* Fix eval benchmark tests, add more
* Improve benchmarks
* Optimizations and refactoring.
* Add lua memtest
* Typo
* Add dependency
* golint fixes
* gofmt fixes
* Add scripting commands to the core/commands.json
* Use ARGV for args inside lua
2017-10-05 18:20:40 +03:00
|
|
|
res = resp.SimpleStringValue("OK")
|
2016-03-28 18:57:41 +03:00
|
|
|
}
|
2016-03-05 02:08:16 +03:00
|
|
|
return
|
2016-10-03 18:31:13 +03:00
|
|
|
notok:
|
|
|
|
switch msg.OutputType {
|
2016-11-09 23:43:26 +03:00
|
|
|
default:
|
2018-10-29 01:49:45 +03:00
|
|
|
case JSON:
|
2016-10-31 20:17:30 +03:00
|
|
|
if nx {
|
|
|
|
err = errIDAlreadyExists
|
|
|
|
} else {
|
|
|
|
err = errIDNotFound
|
|
|
|
}
|
|
|
|
return
|
2018-10-29 01:49:45 +03:00
|
|
|
case RESP:
|
Lua scripting feature. (#224)
* Start on lua scripting
* Implement evalsha, script load, script exists, and script flush
* Type conversions from lua to resp/json.
Refactor to make luastate and luascripts persistent in the controller.
* Change controller.command and all underlying commands to return resp.Value.
Serialize only during the ouput.
* First stab at tile38 call from lua
* Change tile38 into tile38.call in Lua
* Property return errors from scripts
* Minor refactoring. No locking on script run
* Cleanup/refactoring
* Create a pool of 5 lua states, allow for more as needed. Refactor.
* Use safe map for scripts. Add a limit for max number of lua states. Refactor.
* Refactor
* Refactor script commands into atomic, read-only, and non-atomic classes.
Proper locking for all three classes.
Add tests for scripts
* More tests for scripts
* Properly escape newlines in lua-produced errors
* Better test for readonly failure
* Correctly convert ok/err messages between lua and resp.
Add pcall, sha1hex, error_reply, status_reply functions to tile38 namespace in lua.
* Add pcall test. Change writeErr to work with string argument
* Make sure eval/evalsha never attempt to write AOF
* Add eval-set and eval-get to benchmarks
* Fix eval benchmark tests, add more
* Improve benchmarks
* Optimizations and refactoring.
* Add lua memtest
* Typo
* Add dependency
* golint fixes
* gofmt fixes
* Add scripting commands to the core/commands.json
* Use ARGV for args inside lua
2017-10-05 18:20:40 +03:00
|
|
|
res = resp.NullValue()
|
2016-10-03 18:31:13 +03:00
|
|
|
}
|
|
|
|
return
|
2016-03-05 02:08:16 +03:00
|
|
|
}
|
|
|
|
|
2018-10-29 01:49:45 +03:00
|
|
|
func (server *Server) parseFSetArgs(vs []string) (
|
2018-11-24 01:53:33 +03:00
|
|
|
d commandDetails, fields []string, values []float64, xx bool, err error,
|
2017-11-03 21:50:03 +03:00
|
|
|
) {
|
2016-03-28 18:57:41 +03:00
|
|
|
var ok bool
|
|
|
|
if vs, d.key, ok = tokenval(vs); !ok || d.key == "" {
|
2016-03-05 02:08:16 +03:00
|
|
|
err = errInvalidNumberOfArguments
|
|
|
|
return
|
|
|
|
}
|
2016-03-28 18:57:41 +03:00
|
|
|
if vs, d.id, ok = tokenval(vs); !ok || d.id == "" {
|
2016-03-05 02:08:16 +03:00
|
|
|
err = errInvalidNumberOfArguments
|
|
|
|
return
|
|
|
|
}
|
2017-11-03 21:50:03 +03:00
|
|
|
for len(vs) > 0 {
|
|
|
|
var name string
|
|
|
|
if vs, name, ok = tokenval(vs); !ok || name == "" {
|
|
|
|
err = errInvalidNumberOfArguments
|
|
|
|
return
|
|
|
|
}
|
|
|
|
if lc(name, "xx") {
|
|
|
|
xx = true
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
if isReservedFieldName(name) {
|
|
|
|
err = errInvalidArgument(name)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
var svalue string
|
|
|
|
var value float64
|
|
|
|
if vs, svalue, ok = tokenval(vs); !ok || svalue == "" {
|
|
|
|
err = errInvalidNumberOfArguments
|
|
|
|
return
|
|
|
|
}
|
|
|
|
value, err = strconv.ParseFloat(svalue, 64)
|
|
|
|
if err != nil {
|
|
|
|
err = errInvalidArgument(svalue)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
fields = append(fields, name)
|
|
|
|
values = append(values, value)
|
2016-03-05 02:08:16 +03:00
|
|
|
}
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2018-11-24 01:53:33 +03:00
|
|
|
func (server *Server) cmdFset(msg *Message) (res resp.Value, d commandDetails, err error) {
|
2018-10-29 01:49:45 +03:00
|
|
|
if server.config.maxMemory() > 0 && server.outOfMemory.on() {
|
2018-01-24 02:54:10 +03:00
|
|
|
err = errOOM
|
|
|
|
return
|
|
|
|
}
|
2016-03-28 18:57:41 +03:00
|
|
|
start := time.Now()
|
2018-10-29 01:49:45 +03:00
|
|
|
vs := msg.Args[1:]
|
2017-11-03 21:50:03 +03:00
|
|
|
var fields []string
|
|
|
|
var values []float64
|
|
|
|
var xx bool
|
2018-10-11 00:25:40 +03:00
|
|
|
var updateCount int
|
2018-10-29 01:49:45 +03:00
|
|
|
d, fields, values, xx, err = server.parseFSetArgs(vs)
|
2017-11-03 21:50:03 +03:00
|
|
|
|
2018-10-29 01:49:45 +03:00
|
|
|
col := server.getCol(d.key)
|
2016-03-05 02:08:16 +03:00
|
|
|
if col == nil {
|
|
|
|
err = errKeyNotFound
|
|
|
|
return
|
|
|
|
}
|
|
|
|
var ok bool
|
2018-10-11 00:25:40 +03:00
|
|
|
d.obj, d.fields, updateCount, ok = col.SetFields(d.id, fields, values)
|
2017-11-03 21:50:03 +03:00
|
|
|
if !(ok || xx) {
|
2016-03-05 02:08:16 +03:00
|
|
|
err = errIDNotFound
|
|
|
|
return
|
|
|
|
}
|
2017-11-03 21:50:03 +03:00
|
|
|
if ok {
|
|
|
|
d.command = "fset"
|
|
|
|
d.timestamp = time.Now()
|
2018-10-11 00:25:40 +03:00
|
|
|
d.updated = updateCount > 0
|
2017-11-03 21:50:03 +03:00
|
|
|
fmap := col.FieldMap()
|
|
|
|
d.fmap = make(map[string]int)
|
|
|
|
for key, idx := range fmap {
|
|
|
|
d.fmap[key] = idx
|
|
|
|
}
|
2016-04-02 17:20:30 +03:00
|
|
|
}
|
|
|
|
|
2016-03-28 18:57:41 +03:00
|
|
|
switch msg.OutputType {
|
2018-10-29 01:49:45 +03:00
|
|
|
case JSON:
|
Lua scripting feature. (#224)
* Start on lua scripting
* Implement evalsha, script load, script exists, and script flush
* Type conversions from lua to resp/json.
Refactor to make luastate and luascripts persistent in the controller.
* Change controller.command and all underlying commands to return resp.Value.
Serialize only during the ouput.
* First stab at tile38 call from lua
* Change tile38 into tile38.call in Lua
* Property return errors from scripts
* Minor refactoring. No locking on script run
* Cleanup/refactoring
* Create a pool of 5 lua states, allow for more as needed. Refactor.
* Use safe map for scripts. Add a limit for max number of lua states. Refactor.
* Refactor
* Refactor script commands into atomic, read-only, and non-atomic classes.
Proper locking for all three classes.
Add tests for scripts
* More tests for scripts
* Properly escape newlines in lua-produced errors
* Better test for readonly failure
* Correctly convert ok/err messages between lua and resp.
Add pcall, sha1hex, error_reply, status_reply functions to tile38 namespace in lua.
* Add pcall test. Change writeErr to work with string argument
* Make sure eval/evalsha never attempt to write AOF
* Add eval-set and eval-get to benchmarks
* Fix eval benchmark tests, add more
* Improve benchmarks
* Optimizations and refactoring.
* Add lua memtest
* Typo
* Add dependency
* golint fixes
* gofmt fixes
* Add scripting commands to the core/commands.json
* Use ARGV for args inside lua
2017-10-05 18:20:40 +03:00
|
|
|
res = resp.StringValue(`{"ok":true,"elapsed":"` + time.Now().Sub(start).String() + "\"}")
|
2018-10-29 01:49:45 +03:00
|
|
|
case RESP:
|
2018-10-11 00:25:40 +03:00
|
|
|
res = resp.IntegerValue(updateCount)
|
2016-03-28 18:57:41 +03:00
|
|
|
}
|
2016-03-05 02:08:16 +03:00
|
|
|
return
|
|
|
|
}
|
2016-07-15 22:22:48 +03:00
|
|
|
|
2018-11-24 01:53:33 +03:00
|
|
|
func (server *Server) cmdExpire(msg *Message) (res resp.Value, d commandDetails, err error) {
|
2016-07-15 22:22:48 +03:00
|
|
|
start := time.Now()
|
2018-10-29 01:49:45 +03:00
|
|
|
vs := msg.Args[1:]
|
2016-07-15 22:22:48 +03:00
|
|
|
var key, id, svalue string
|
|
|
|
var ok bool
|
|
|
|
if vs, key, ok = tokenval(vs); !ok || key == "" {
|
|
|
|
err = errInvalidNumberOfArguments
|
|
|
|
return
|
|
|
|
}
|
|
|
|
if vs, id, ok = tokenval(vs); !ok || id == "" {
|
|
|
|
err = errInvalidNumberOfArguments
|
|
|
|
return
|
|
|
|
}
|
|
|
|
if vs, svalue, ok = tokenval(vs); !ok || svalue == "" {
|
|
|
|
err = errInvalidNumberOfArguments
|
|
|
|
return
|
|
|
|
}
|
|
|
|
if len(vs) != 0 {
|
|
|
|
err = errInvalidNumberOfArguments
|
|
|
|
return
|
|
|
|
}
|
|
|
|
var value float64
|
|
|
|
value, err = strconv.ParseFloat(svalue, 64)
|
|
|
|
if err != nil {
|
|
|
|
err = errInvalidArgument(svalue)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
ok = false
|
2018-10-29 01:49:45 +03:00
|
|
|
col := server.getCol(key)
|
2016-07-15 22:22:48 +03:00
|
|
|
if col != nil {
|
|
|
|
_, _, ok = col.Get(id)
|
2018-10-29 01:49:45 +03:00
|
|
|
ok = ok && !server.hasExpired(key, id)
|
2017-03-29 22:50:04 +03:00
|
|
|
}
|
|
|
|
if ok {
|
2018-10-29 01:49:45 +03:00
|
|
|
server.expireAt(key, id, time.Now().Add(time.Duration(float64(time.Second)*value)))
|
2017-03-29 22:50:04 +03:00
|
|
|
d.updated = true
|
2016-07-15 22:22:48 +03:00
|
|
|
}
|
|
|
|
switch msg.OutputType {
|
2018-10-29 01:49:45 +03:00
|
|
|
case JSON:
|
2017-03-29 22:50:04 +03:00
|
|
|
if ok {
|
Lua scripting feature. (#224)
* Start on lua scripting
* Implement evalsha, script load, script exists, and script flush
* Type conversions from lua to resp/json.
Refactor to make luastate and luascripts persistent in the controller.
* Change controller.command and all underlying commands to return resp.Value.
Serialize only during the ouput.
* First stab at tile38 call from lua
* Change tile38 into tile38.call in Lua
* Property return errors from scripts
* Minor refactoring. No locking on script run
* Cleanup/refactoring
* Create a pool of 5 lua states, allow for more as needed. Refactor.
* Use safe map for scripts. Add a limit for max number of lua states. Refactor.
* Refactor
* Refactor script commands into atomic, read-only, and non-atomic classes.
Proper locking for all three classes.
Add tests for scripts
* More tests for scripts
* Properly escape newlines in lua-produced errors
* Better test for readonly failure
* Correctly convert ok/err messages between lua and resp.
Add pcall, sha1hex, error_reply, status_reply functions to tile38 namespace in lua.
* Add pcall test. Change writeErr to work with string argument
* Make sure eval/evalsha never attempt to write AOF
* Add eval-set and eval-get to benchmarks
* Fix eval benchmark tests, add more
* Improve benchmarks
* Optimizations and refactoring.
* Add lua memtest
* Typo
* Add dependency
* golint fixes
* gofmt fixes
* Add scripting commands to the core/commands.json
* Use ARGV for args inside lua
2017-10-05 18:20:40 +03:00
|
|
|
res = resp.StringValue(`{"ok":true,"elapsed":"` + time.Now().Sub(start).String() + "\"}")
|
2017-03-29 22:50:04 +03:00
|
|
|
} else {
|
Lua scripting feature. (#224)
* Start on lua scripting
* Implement evalsha, script load, script exists, and script flush
* Type conversions from lua to resp/json.
Refactor to make luastate and luascripts persistent in the controller.
* Change controller.command and all underlying commands to return resp.Value.
Serialize only during the ouput.
* First stab at tile38 call from lua
* Change tile38 into tile38.call in Lua
* Property return errors from scripts
* Minor refactoring. No locking on script run
* Cleanup/refactoring
* Create a pool of 5 lua states, allow for more as needed. Refactor.
* Use safe map for scripts. Add a limit for max number of lua states. Refactor.
* Refactor
* Refactor script commands into atomic, read-only, and non-atomic classes.
Proper locking for all three classes.
Add tests for scripts
* More tests for scripts
* Properly escape newlines in lua-produced errors
* Better test for readonly failure
* Correctly convert ok/err messages between lua and resp.
Add pcall, sha1hex, error_reply, status_reply functions to tile38 namespace in lua.
* Add pcall test. Change writeErr to work with string argument
* Make sure eval/evalsha never attempt to write AOF
* Add eval-set and eval-get to benchmarks
* Fix eval benchmark tests, add more
* Improve benchmarks
* Optimizations and refactoring.
* Add lua memtest
* Typo
* Add dependency
* golint fixes
* gofmt fixes
* Add scripting commands to the core/commands.json
* Use ARGV for args inside lua
2017-10-05 18:20:40 +03:00
|
|
|
return resp.SimpleStringValue(""), d, errIDNotFound
|
2017-03-29 22:50:04 +03:00
|
|
|
}
|
2018-10-29 01:49:45 +03:00
|
|
|
case RESP:
|
2016-07-15 22:22:48 +03:00
|
|
|
if ok {
|
Lua scripting feature. (#224)
* Start on lua scripting
* Implement evalsha, script load, script exists, and script flush
* Type conversions from lua to resp/json.
Refactor to make luastate and luascripts persistent in the controller.
* Change controller.command and all underlying commands to return resp.Value.
Serialize only during the ouput.
* First stab at tile38 call from lua
* Change tile38 into tile38.call in Lua
* Property return errors from scripts
* Minor refactoring. No locking on script run
* Cleanup/refactoring
* Create a pool of 5 lua states, allow for more as needed. Refactor.
* Use safe map for scripts. Add a limit for max number of lua states. Refactor.
* Refactor
* Refactor script commands into atomic, read-only, and non-atomic classes.
Proper locking for all three classes.
Add tests for scripts
* More tests for scripts
* Properly escape newlines in lua-produced errors
* Better test for readonly failure
* Correctly convert ok/err messages between lua and resp.
Add pcall, sha1hex, error_reply, status_reply functions to tile38 namespace in lua.
* Add pcall test. Change writeErr to work with string argument
* Make sure eval/evalsha never attempt to write AOF
* Add eval-set and eval-get to benchmarks
* Fix eval benchmark tests, add more
* Improve benchmarks
* Optimizations and refactoring.
* Add lua memtest
* Typo
* Add dependency
* golint fixes
* gofmt fixes
* Add scripting commands to the core/commands.json
* Use ARGV for args inside lua
2017-10-05 18:20:40 +03:00
|
|
|
res = resp.IntegerValue(1)
|
2016-07-15 22:22:48 +03:00
|
|
|
} else {
|
Lua scripting feature. (#224)
* Start on lua scripting
* Implement evalsha, script load, script exists, and script flush
* Type conversions from lua to resp/json.
Refactor to make luastate and luascripts persistent in the controller.
* Change controller.command and all underlying commands to return resp.Value.
Serialize only during the ouput.
* First stab at tile38 call from lua
* Change tile38 into tile38.call in Lua
* Property return errors from scripts
* Minor refactoring. No locking on script run
* Cleanup/refactoring
* Create a pool of 5 lua states, allow for more as needed. Refactor.
* Use safe map for scripts. Add a limit for max number of lua states. Refactor.
* Refactor
* Refactor script commands into atomic, read-only, and non-atomic classes.
Proper locking for all three classes.
Add tests for scripts
* More tests for scripts
* Properly escape newlines in lua-produced errors
* Better test for readonly failure
* Correctly convert ok/err messages between lua and resp.
Add pcall, sha1hex, error_reply, status_reply functions to tile38 namespace in lua.
* Add pcall test. Change writeErr to work with string argument
* Make sure eval/evalsha never attempt to write AOF
* Add eval-set and eval-get to benchmarks
* Fix eval benchmark tests, add more
* Improve benchmarks
* Optimizations and refactoring.
* Add lua memtest
* Typo
* Add dependency
* golint fixes
* gofmt fixes
* Add scripting commands to the core/commands.json
* Use ARGV for args inside lua
2017-10-05 18:20:40 +03:00
|
|
|
res = resp.IntegerValue(0)
|
2016-07-15 22:22:48 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2018-11-24 01:53:33 +03:00
|
|
|
func (server *Server) cmdPersist(msg *Message) (res resp.Value, d commandDetails, err error) {
|
2016-07-15 22:22:48 +03:00
|
|
|
start := time.Now()
|
2018-10-29 01:49:45 +03:00
|
|
|
vs := msg.Args[1:]
|
2016-07-15 22:22:48 +03:00
|
|
|
var key, id string
|
|
|
|
var ok bool
|
|
|
|
if vs, key, ok = tokenval(vs); !ok || key == "" {
|
|
|
|
err = errInvalidNumberOfArguments
|
|
|
|
return
|
|
|
|
}
|
|
|
|
if vs, id, ok = tokenval(vs); !ok || id == "" {
|
|
|
|
err = errInvalidNumberOfArguments
|
|
|
|
return
|
|
|
|
}
|
|
|
|
if len(vs) != 0 {
|
|
|
|
err = errInvalidNumberOfArguments
|
|
|
|
return
|
|
|
|
}
|
2017-03-29 22:50:04 +03:00
|
|
|
var cleared bool
|
2016-07-15 22:22:48 +03:00
|
|
|
ok = false
|
2018-10-29 01:49:45 +03:00
|
|
|
col := server.getCol(key)
|
2016-07-15 22:22:48 +03:00
|
|
|
if col != nil {
|
|
|
|
_, _, ok = col.Get(id)
|
2018-10-29 01:49:45 +03:00
|
|
|
ok = ok && !server.hasExpired(key, id)
|
2016-07-15 22:22:48 +03:00
|
|
|
if ok {
|
2018-10-29 01:49:45 +03:00
|
|
|
cleared = server.clearIDExpires(key, id)
|
2017-03-29 22:50:04 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if !ok {
|
2018-10-29 01:49:45 +03:00
|
|
|
if msg.OutputType == RESP {
|
Lua scripting feature. (#224)
* Start on lua scripting
* Implement evalsha, script load, script exists, and script flush
* Type conversions from lua to resp/json.
Refactor to make luastate and luascripts persistent in the controller.
* Change controller.command and all underlying commands to return resp.Value.
Serialize only during the ouput.
* First stab at tile38 call from lua
* Change tile38 into tile38.call in Lua
* Property return errors from scripts
* Minor refactoring. No locking on script run
* Cleanup/refactoring
* Create a pool of 5 lua states, allow for more as needed. Refactor.
* Use safe map for scripts. Add a limit for max number of lua states. Refactor.
* Refactor
* Refactor script commands into atomic, read-only, and non-atomic classes.
Proper locking for all three classes.
Add tests for scripts
* More tests for scripts
* Properly escape newlines in lua-produced errors
* Better test for readonly failure
* Correctly convert ok/err messages between lua and resp.
Add pcall, sha1hex, error_reply, status_reply functions to tile38 namespace in lua.
* Add pcall test. Change writeErr to work with string argument
* Make sure eval/evalsha never attempt to write AOF
* Add eval-set and eval-get to benchmarks
* Fix eval benchmark tests, add more
* Improve benchmarks
* Optimizations and refactoring.
* Add lua memtest
* Typo
* Add dependency
* golint fixes
* gofmt fixes
* Add scripting commands to the core/commands.json
* Use ARGV for args inside lua
2017-10-05 18:20:40 +03:00
|
|
|
return resp.IntegerValue(0), d, nil
|
2016-07-15 22:22:48 +03:00
|
|
|
}
|
Lua scripting feature. (#224)
* Start on lua scripting
* Implement evalsha, script load, script exists, and script flush
* Type conversions from lua to resp/json.
Refactor to make luastate and luascripts persistent in the controller.
* Change controller.command and all underlying commands to return resp.Value.
Serialize only during the ouput.
* First stab at tile38 call from lua
* Change tile38 into tile38.call in Lua
* Property return errors from scripts
* Minor refactoring. No locking on script run
* Cleanup/refactoring
* Create a pool of 5 lua states, allow for more as needed. Refactor.
* Use safe map for scripts. Add a limit for max number of lua states. Refactor.
* Refactor
* Refactor script commands into atomic, read-only, and non-atomic classes.
Proper locking for all three classes.
Add tests for scripts
* More tests for scripts
* Properly escape newlines in lua-produced errors
* Better test for readonly failure
* Correctly convert ok/err messages between lua and resp.
Add pcall, sha1hex, error_reply, status_reply functions to tile38 namespace in lua.
* Add pcall test. Change writeErr to work with string argument
* Make sure eval/evalsha never attempt to write AOF
* Add eval-set and eval-get to benchmarks
* Fix eval benchmark tests, add more
* Improve benchmarks
* Optimizations and refactoring.
* Add lua memtest
* Typo
* Add dependency
* golint fixes
* gofmt fixes
* Add scripting commands to the core/commands.json
* Use ARGV for args inside lua
2017-10-05 18:20:40 +03:00
|
|
|
return resp.SimpleStringValue(""), d, errIDNotFound
|
2016-07-15 22:22:48 +03:00
|
|
|
}
|
2017-03-29 22:50:04 +03:00
|
|
|
d.command = "persist"
|
|
|
|
d.updated = cleared
|
|
|
|
d.timestamp = time.Now()
|
2016-07-15 22:22:48 +03:00
|
|
|
switch msg.OutputType {
|
2018-10-29 01:49:45 +03:00
|
|
|
case JSON:
|
Lua scripting feature. (#224)
* Start on lua scripting
* Implement evalsha, script load, script exists, and script flush
* Type conversions from lua to resp/json.
Refactor to make luastate and luascripts persistent in the controller.
* Change controller.command and all underlying commands to return resp.Value.
Serialize only during the ouput.
* First stab at tile38 call from lua
* Change tile38 into tile38.call in Lua
* Property return errors from scripts
* Minor refactoring. No locking on script run
* Cleanup/refactoring
* Create a pool of 5 lua states, allow for more as needed. Refactor.
* Use safe map for scripts. Add a limit for max number of lua states. Refactor.
* Refactor
* Refactor script commands into atomic, read-only, and non-atomic classes.
Proper locking for all three classes.
Add tests for scripts
* More tests for scripts
* Properly escape newlines in lua-produced errors
* Better test for readonly failure
* Correctly convert ok/err messages between lua and resp.
Add pcall, sha1hex, error_reply, status_reply functions to tile38 namespace in lua.
* Add pcall test. Change writeErr to work with string argument
* Make sure eval/evalsha never attempt to write AOF
* Add eval-set and eval-get to benchmarks
* Fix eval benchmark tests, add more
* Improve benchmarks
* Optimizations and refactoring.
* Add lua memtest
* Typo
* Add dependency
* golint fixes
* gofmt fixes
* Add scripting commands to the core/commands.json
* Use ARGV for args inside lua
2017-10-05 18:20:40 +03:00
|
|
|
res = resp.SimpleStringValue(`{"ok":true,"elapsed":"` + time.Now().Sub(start).String() + "\"}")
|
2018-10-29 01:49:45 +03:00
|
|
|
case RESP:
|
2017-03-29 22:50:04 +03:00
|
|
|
if cleared {
|
Lua scripting feature. (#224)
* Start on lua scripting
* Implement evalsha, script load, script exists, and script flush
* Type conversions from lua to resp/json.
Refactor to make luastate and luascripts persistent in the controller.
* Change controller.command and all underlying commands to return resp.Value.
Serialize only during the ouput.
* First stab at tile38 call from lua
* Change tile38 into tile38.call in Lua
* Property return errors from scripts
* Minor refactoring. No locking on script run
* Cleanup/refactoring
* Create a pool of 5 lua states, allow for more as needed. Refactor.
* Use safe map for scripts. Add a limit for max number of lua states. Refactor.
* Refactor
* Refactor script commands into atomic, read-only, and non-atomic classes.
Proper locking for all three classes.
Add tests for scripts
* More tests for scripts
* Properly escape newlines in lua-produced errors
* Better test for readonly failure
* Correctly convert ok/err messages between lua and resp.
Add pcall, sha1hex, error_reply, status_reply functions to tile38 namespace in lua.
* Add pcall test. Change writeErr to work with string argument
* Make sure eval/evalsha never attempt to write AOF
* Add eval-set and eval-get to benchmarks
* Fix eval benchmark tests, add more
* Improve benchmarks
* Optimizations and refactoring.
* Add lua memtest
* Typo
* Add dependency
* golint fixes
* gofmt fixes
* Add scripting commands to the core/commands.json
* Use ARGV for args inside lua
2017-10-05 18:20:40 +03:00
|
|
|
res = resp.IntegerValue(1)
|
2016-07-15 22:22:48 +03:00
|
|
|
} else {
|
Lua scripting feature. (#224)
* Start on lua scripting
* Implement evalsha, script load, script exists, and script flush
* Type conversions from lua to resp/json.
Refactor to make luastate and luascripts persistent in the controller.
* Change controller.command and all underlying commands to return resp.Value.
Serialize only during the ouput.
* First stab at tile38 call from lua
* Change tile38 into tile38.call in Lua
* Property return errors from scripts
* Minor refactoring. No locking on script run
* Cleanup/refactoring
* Create a pool of 5 lua states, allow for more as needed. Refactor.
* Use safe map for scripts. Add a limit for max number of lua states. Refactor.
* Refactor
* Refactor script commands into atomic, read-only, and non-atomic classes.
Proper locking for all three classes.
Add tests for scripts
* More tests for scripts
* Properly escape newlines in lua-produced errors
* Better test for readonly failure
* Correctly convert ok/err messages between lua and resp.
Add pcall, sha1hex, error_reply, status_reply functions to tile38 namespace in lua.
* Add pcall test. Change writeErr to work with string argument
* Make sure eval/evalsha never attempt to write AOF
* Add eval-set and eval-get to benchmarks
* Fix eval benchmark tests, add more
* Improve benchmarks
* Optimizations and refactoring.
* Add lua memtest
* Typo
* Add dependency
* golint fixes
* gofmt fixes
* Add scripting commands to the core/commands.json
* Use ARGV for args inside lua
2017-10-05 18:20:40 +03:00
|
|
|
res = resp.IntegerValue(0)
|
2016-07-15 22:22:48 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2018-10-29 01:49:45 +03:00
|
|
|
func (server *Server) cmdTTL(msg *Message) (res resp.Value, err error) {
|
2016-07-15 22:22:48 +03:00
|
|
|
start := time.Now()
|
2018-10-29 01:49:45 +03:00
|
|
|
vs := msg.Args[1:]
|
2016-07-15 22:22:48 +03:00
|
|
|
var key, id string
|
|
|
|
var ok bool
|
|
|
|
if vs, key, ok = tokenval(vs); !ok || key == "" {
|
|
|
|
err = errInvalidNumberOfArguments
|
|
|
|
return
|
|
|
|
}
|
|
|
|
if vs, id, ok = tokenval(vs); !ok || id == "" {
|
|
|
|
err = errInvalidNumberOfArguments
|
|
|
|
return
|
|
|
|
}
|
|
|
|
if len(vs) != 0 {
|
|
|
|
err = errInvalidNumberOfArguments
|
|
|
|
return
|
|
|
|
}
|
|
|
|
var v float64
|
|
|
|
ok = false
|
|
|
|
var ok2 bool
|
2018-10-29 01:49:45 +03:00
|
|
|
col := server.getCol(key)
|
2016-07-15 22:22:48 +03:00
|
|
|
if col != nil {
|
|
|
|
_, _, ok = col.Get(id)
|
2018-10-29 01:49:45 +03:00
|
|
|
ok = ok && !server.hasExpired(key, id)
|
2016-07-15 22:22:48 +03:00
|
|
|
if ok {
|
|
|
|
var at time.Time
|
2018-10-29 01:49:45 +03:00
|
|
|
at, ok2 = server.getExpires(key, id)
|
2016-07-15 22:22:48 +03:00
|
|
|
if ok2 {
|
2017-03-29 22:50:04 +03:00
|
|
|
if time.Now().After(at) {
|
|
|
|
ok2 = false
|
|
|
|
} else {
|
|
|
|
v = float64(at.Sub(time.Now())) / float64(time.Second)
|
|
|
|
if v < 0 {
|
|
|
|
v = 0
|
|
|
|
}
|
2016-07-15 22:22:48 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
switch msg.OutputType {
|
2018-10-29 01:49:45 +03:00
|
|
|
case JSON:
|
2017-01-07 19:27:36 +03:00
|
|
|
if ok {
|
|
|
|
var ttl string
|
|
|
|
if ok2 {
|
|
|
|
ttl = strconv.FormatFloat(v, 'f', -1, 64)
|
|
|
|
} else {
|
|
|
|
ttl = "-1"
|
|
|
|
}
|
Lua scripting feature. (#224)
* Start on lua scripting
* Implement evalsha, script load, script exists, and script flush
* Type conversions from lua to resp/json.
Refactor to make luastate and luascripts persistent in the controller.
* Change controller.command and all underlying commands to return resp.Value.
Serialize only during the ouput.
* First stab at tile38 call from lua
* Change tile38 into tile38.call in Lua
* Property return errors from scripts
* Minor refactoring. No locking on script run
* Cleanup/refactoring
* Create a pool of 5 lua states, allow for more as needed. Refactor.
* Use safe map for scripts. Add a limit for max number of lua states. Refactor.
* Refactor
* Refactor script commands into atomic, read-only, and non-atomic classes.
Proper locking for all three classes.
Add tests for scripts
* More tests for scripts
* Properly escape newlines in lua-produced errors
* Better test for readonly failure
* Correctly convert ok/err messages between lua and resp.
Add pcall, sha1hex, error_reply, status_reply functions to tile38 namespace in lua.
* Add pcall test. Change writeErr to work with string argument
* Make sure eval/evalsha never attempt to write AOF
* Add eval-set and eval-get to benchmarks
* Fix eval benchmark tests, add more
* Improve benchmarks
* Optimizations and refactoring.
* Add lua memtest
* Typo
* Add dependency
* golint fixes
* gofmt fixes
* Add scripting commands to the core/commands.json
* Use ARGV for args inside lua
2017-10-05 18:20:40 +03:00
|
|
|
res = resp.SimpleStringValue(
|
|
|
|
`{"ok":true,"ttl":` + ttl + `,"elapsed":"` + time.Now().Sub(start).String() + "\"}")
|
2017-01-07 19:27:36 +03:00
|
|
|
} else {
|
Lua scripting feature. (#224)
* Start on lua scripting
* Implement evalsha, script load, script exists, and script flush
* Type conversions from lua to resp/json.
Refactor to make luastate and luascripts persistent in the controller.
* Change controller.command and all underlying commands to return resp.Value.
Serialize only during the ouput.
* First stab at tile38 call from lua
* Change tile38 into tile38.call in Lua
* Property return errors from scripts
* Minor refactoring. No locking on script run
* Cleanup/refactoring
* Create a pool of 5 lua states, allow for more as needed. Refactor.
* Use safe map for scripts. Add a limit for max number of lua states. Refactor.
* Refactor
* Refactor script commands into atomic, read-only, and non-atomic classes.
Proper locking for all three classes.
Add tests for scripts
* More tests for scripts
* Properly escape newlines in lua-produced errors
* Better test for readonly failure
* Correctly convert ok/err messages between lua and resp.
Add pcall, sha1hex, error_reply, status_reply functions to tile38 namespace in lua.
* Add pcall test. Change writeErr to work with string argument
* Make sure eval/evalsha never attempt to write AOF
* Add eval-set and eval-get to benchmarks
* Fix eval benchmark tests, add more
* Improve benchmarks
* Optimizations and refactoring.
* Add lua memtest
* Typo
* Add dependency
* golint fixes
* gofmt fixes
* Add scripting commands to the core/commands.json
* Use ARGV for args inside lua
2017-10-05 18:20:40 +03:00
|
|
|
return resp.SimpleStringValue(""), errIDNotFound
|
2017-01-07 19:27:36 +03:00
|
|
|
}
|
2018-10-29 01:49:45 +03:00
|
|
|
case RESP:
|
2016-07-15 22:22:48 +03:00
|
|
|
if ok {
|
|
|
|
if ok2 {
|
Lua scripting feature. (#224)
* Start on lua scripting
* Implement evalsha, script load, script exists, and script flush
* Type conversions from lua to resp/json.
Refactor to make luastate and luascripts persistent in the controller.
* Change controller.command and all underlying commands to return resp.Value.
Serialize only during the ouput.
* First stab at tile38 call from lua
* Change tile38 into tile38.call in Lua
* Property return errors from scripts
* Minor refactoring. No locking on script run
* Cleanup/refactoring
* Create a pool of 5 lua states, allow for more as needed. Refactor.
* Use safe map for scripts. Add a limit for max number of lua states. Refactor.
* Refactor
* Refactor script commands into atomic, read-only, and non-atomic classes.
Proper locking for all three classes.
Add tests for scripts
* More tests for scripts
* Properly escape newlines in lua-produced errors
* Better test for readonly failure
* Correctly convert ok/err messages between lua and resp.
Add pcall, sha1hex, error_reply, status_reply functions to tile38 namespace in lua.
* Add pcall test. Change writeErr to work with string argument
* Make sure eval/evalsha never attempt to write AOF
* Add eval-set and eval-get to benchmarks
* Fix eval benchmark tests, add more
* Improve benchmarks
* Optimizations and refactoring.
* Add lua memtest
* Typo
* Add dependency
* golint fixes
* gofmt fixes
* Add scripting commands to the core/commands.json
* Use ARGV for args inside lua
2017-10-05 18:20:40 +03:00
|
|
|
res = resp.IntegerValue(int(v))
|
2016-07-15 22:22:48 +03:00
|
|
|
} else {
|
Lua scripting feature. (#224)
* Start on lua scripting
* Implement evalsha, script load, script exists, and script flush
* Type conversions from lua to resp/json.
Refactor to make luastate and luascripts persistent in the controller.
* Change controller.command and all underlying commands to return resp.Value.
Serialize only during the ouput.
* First stab at tile38 call from lua
* Change tile38 into tile38.call in Lua
* Property return errors from scripts
* Minor refactoring. No locking on script run
* Cleanup/refactoring
* Create a pool of 5 lua states, allow for more as needed. Refactor.
* Use safe map for scripts. Add a limit for max number of lua states. Refactor.
* Refactor
* Refactor script commands into atomic, read-only, and non-atomic classes.
Proper locking for all three classes.
Add tests for scripts
* More tests for scripts
* Properly escape newlines in lua-produced errors
* Better test for readonly failure
* Correctly convert ok/err messages between lua and resp.
Add pcall, sha1hex, error_reply, status_reply functions to tile38 namespace in lua.
* Add pcall test. Change writeErr to work with string argument
* Make sure eval/evalsha never attempt to write AOF
* Add eval-set and eval-get to benchmarks
* Fix eval benchmark tests, add more
* Improve benchmarks
* Optimizations and refactoring.
* Add lua memtest
* Typo
* Add dependency
* golint fixes
* gofmt fixes
* Add scripting commands to the core/commands.json
* Use ARGV for args inside lua
2017-10-05 18:20:40 +03:00
|
|
|
res = resp.IntegerValue(-1)
|
2016-07-15 22:22:48 +03:00
|
|
|
}
|
|
|
|
} else {
|
Lua scripting feature. (#224)
* Start on lua scripting
* Implement evalsha, script load, script exists, and script flush
* Type conversions from lua to resp/json.
Refactor to make luastate and luascripts persistent in the controller.
* Change controller.command and all underlying commands to return resp.Value.
Serialize only during the ouput.
* First stab at tile38 call from lua
* Change tile38 into tile38.call in Lua
* Property return errors from scripts
* Minor refactoring. No locking on script run
* Cleanup/refactoring
* Create a pool of 5 lua states, allow for more as needed. Refactor.
* Use safe map for scripts. Add a limit for max number of lua states. Refactor.
* Refactor
* Refactor script commands into atomic, read-only, and non-atomic classes.
Proper locking for all three classes.
Add tests for scripts
* More tests for scripts
* Properly escape newlines in lua-produced errors
* Better test for readonly failure
* Correctly convert ok/err messages between lua and resp.
Add pcall, sha1hex, error_reply, status_reply functions to tile38 namespace in lua.
* Add pcall test. Change writeErr to work with string argument
* Make sure eval/evalsha never attempt to write AOF
* Add eval-set and eval-get to benchmarks
* Fix eval benchmark tests, add more
* Improve benchmarks
* Optimizations and refactoring.
* Add lua memtest
* Typo
* Add dependency
* golint fixes
* gofmt fixes
* Add scripting commands to the core/commands.json
* Use ARGV for args inside lua
2017-10-05 18:20:40 +03:00
|
|
|
res = resp.IntegerValue(-2)
|
2016-07-15 22:22:48 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return
|
|
|
|
}
|