2018-10-29 01:49:45 +03:00
|
|
|
package server
|
2016-03-05 02:08:16 +03:00
|
|
|
|
2016-12-12 20:33:28 +03:00
|
|
|
import (
|
|
|
|
"bytes"
|
|
|
|
"encoding/json"
|
|
|
|
"strconv"
|
|
|
|
"strings"
|
|
|
|
"time"
|
|
|
|
|
2018-10-11 00:25:40 +03:00
|
|
|
"github.com/tidwall/geojson"
|
2016-12-12 20:33:28 +03:00
|
|
|
"github.com/tidwall/gjson"
|
|
|
|
"github.com/tidwall/resp"
|
|
|
|
"github.com/tidwall/sjson"
|
2018-10-11 00:25:40 +03:00
|
|
|
"github.com/tidwall/tile38/internal/collection"
|
2016-12-12 20:33:28 +03:00
|
|
|
)
|
2016-03-05 02:08:16 +03:00
|
|
|
|
2016-12-28 21:16:28 +03:00
|
|
|
func appendJSONString(b []byte, s string) []byte {
|
|
|
|
for i := 0; i < len(s); i++ {
|
|
|
|
if s[i] < ' ' || s[i] == '\\' || s[i] == '"' || s[i] > 126 {
|
|
|
|
d, _ := json.Marshal(s)
|
|
|
|
return append(b, string(d)...)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
b = append(b, '"')
|
|
|
|
b = append(b, s...)
|
|
|
|
b = append(b, '"')
|
|
|
|
return b
|
|
|
|
}
|
|
|
|
|
2016-03-05 02:08:16 +03:00
|
|
|
func jsonString(s string) string {
|
|
|
|
for i := 0; i < len(s); i++ {
|
2016-09-11 17:49:48 +03:00
|
|
|
if s[i] < ' ' || s[i] == '\\' || s[i] == '"' || s[i] > 126 {
|
2016-03-05 02:08:16 +03:00
|
|
|
d, _ := json.Marshal(s)
|
|
|
|
return string(d)
|
|
|
|
}
|
|
|
|
}
|
2016-09-11 17:49:48 +03:00
|
|
|
b := make([]byte, len(s)+2)
|
|
|
|
b[0] = '"'
|
2016-11-07 23:04:21 +03:00
|
|
|
copy(b[1:], s)
|
2016-09-11 17:49:48 +03:00
|
|
|
b[len(b)-1] = '"'
|
2016-11-07 23:04:21 +03:00
|
|
|
return string(b)
|
2016-03-05 02:08:16 +03:00
|
|
|
}
|
2019-10-27 05:33:35 +03:00
|
|
|
|
2019-10-30 20:17:59 +03:00
|
|
|
func isJSONNumber(data string) bool {
|
2019-10-27 05:33:35 +03:00
|
|
|
// Returns true if the given string can be encoded as a JSON number value.
|
|
|
|
// See:
|
|
|
|
// https://json.org
|
|
|
|
// http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf
|
2019-10-29 04:35:44 +03:00
|
|
|
if data == "" {
|
2019-10-27 05:33:35 +03:00
|
|
|
return false
|
|
|
|
}
|
|
|
|
i := 0
|
2019-10-29 04:35:44 +03:00
|
|
|
// sign
|
|
|
|
if data[i] == '-' {
|
2019-10-27 05:33:35 +03:00
|
|
|
i++
|
|
|
|
}
|
2019-10-29 04:35:44 +03:00
|
|
|
if i == len(data) {
|
2019-10-27 05:33:35 +03:00
|
|
|
return false
|
2019-10-29 04:35:44 +03:00
|
|
|
}
|
|
|
|
// int
|
|
|
|
if data[i] == '0' {
|
2019-10-27 05:33:35 +03:00
|
|
|
i++
|
2019-10-29 04:35:44 +03:00
|
|
|
} else {
|
|
|
|
for ; i < len(data); i++ {
|
|
|
|
if data[i] >= '0' && data[i] <= '9' {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
break
|
2019-10-27 05:33:35 +03:00
|
|
|
}
|
|
|
|
}
|
2019-10-29 04:35:44 +03:00
|
|
|
// frac
|
|
|
|
if i == len(data) {
|
2019-10-27 05:33:35 +03:00
|
|
|
return true
|
|
|
|
}
|
2019-10-29 04:35:44 +03:00
|
|
|
if data[i] == '.' {
|
|
|
|
i++
|
|
|
|
if i == len(data) {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
if data[i] < '0' || data[i] > '9' {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
i++
|
|
|
|
for ; i < len(data); i++ {
|
|
|
|
if data[i] >= '0' && data[i] <= '9' {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
break
|
2019-10-27 05:33:35 +03:00
|
|
|
}
|
|
|
|
}
|
2019-10-29 04:35:44 +03:00
|
|
|
// exp
|
|
|
|
if i == len(data) {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
if data[i] == 'e' || data[i] == 'E' {
|
2019-10-27 05:33:35 +03:00
|
|
|
i++
|
2019-10-29 04:35:44 +03:00
|
|
|
if i == len(data) {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
if data[i] == '+' || data[i] == '-' {
|
2019-10-27 05:33:35 +03:00
|
|
|
i++
|
|
|
|
}
|
2019-10-29 04:35:44 +03:00
|
|
|
if i == len(data) {
|
2019-10-27 05:33:35 +03:00
|
|
|
return false
|
2019-10-29 04:35:44 +03:00
|
|
|
}
|
|
|
|
if data[i] < '0' || data[i] > '9' {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
i++
|
|
|
|
for ; i < len(data); i++ {
|
|
|
|
if data[i] >= '0' && data[i] <= '9' {
|
|
|
|
continue
|
2019-10-27 05:33:35 +03:00
|
|
|
}
|
2019-10-29 04:35:44 +03:00
|
|
|
break
|
2019-10-27 05:33:35 +03:00
|
|
|
}
|
|
|
|
}
|
2019-10-29 04:35:44 +03:00
|
|
|
return i == len(data)
|
2019-10-27 05:33:35 +03:00
|
|
|
}
|
|
|
|
|
2018-10-11 00:25:40 +03:00
|
|
|
func appendJSONSimpleBounds(dst []byte, o geojson.Object) []byte {
|
|
|
|
bbox := o.Rect()
|
|
|
|
dst = append(dst, `{"sw":{"lat":`...)
|
|
|
|
dst = strconv.AppendFloat(dst, bbox.Min.Y, 'f', -1, 64)
|
|
|
|
dst = append(dst, `,"lon":`...)
|
|
|
|
dst = strconv.AppendFloat(dst, bbox.Min.X, 'f', -1, 64)
|
|
|
|
dst = append(dst, `},"ne":{"lat":`...)
|
|
|
|
dst = strconv.AppendFloat(dst, bbox.Max.Y, 'f', -1, 64)
|
|
|
|
dst = append(dst, `,"lon":`...)
|
|
|
|
dst = strconv.AppendFloat(dst, bbox.Max.X, 'f', -1, 64)
|
|
|
|
dst = append(dst, `}}`...)
|
|
|
|
return dst
|
|
|
|
}
|
|
|
|
|
|
|
|
func appendJSONSimplePoint(dst []byte, o geojson.Object) []byte {
|
|
|
|
point := o.Center()
|
|
|
|
var z float64
|
|
|
|
if gPoint, ok := o.(*geojson.Point); ok {
|
|
|
|
z = gPoint.Z()
|
|
|
|
}
|
|
|
|
dst = append(dst, `{"lat":`...)
|
|
|
|
dst = strconv.AppendFloat(dst, point.Y, 'f', -1, 64)
|
|
|
|
dst = append(dst, `,"lon":`...)
|
|
|
|
dst = strconv.AppendFloat(dst, point.X, 'f', -1, 64)
|
|
|
|
if z != 0 {
|
|
|
|
dst = append(dst, `,"z":`...)
|
|
|
|
dst = strconv.AppendFloat(dst, z, 'f', -1, 64)
|
|
|
|
}
|
|
|
|
dst = append(dst, '}')
|
|
|
|
return dst
|
|
|
|
}
|
2016-12-12 20:33:28 +03:00
|
|
|
|
2018-08-03 03:36:18 +03:00
|
|
|
func appendJSONTimeFormat(b []byte, t time.Time) []byte {
|
|
|
|
b = append(b, '"')
|
|
|
|
b = t.AppendFormat(b, "2006-01-02T15:04:05.999999999Z07:00")
|
|
|
|
b = append(b, '"')
|
|
|
|
return b
|
|
|
|
}
|
|
|
|
|
|
|
|
func jsonTimeFormat(t time.Time) string {
|
|
|
|
var b []byte
|
|
|
|
b = appendJSONTimeFormat(b, t)
|
|
|
|
return string(b)
|
|
|
|
}
|
|
|
|
|
2019-10-30 20:17:59 +03:00
|
|
|
func (s *Server) cmdJget(msg *Message) (resp.Value, error) {
|
2016-12-12 20:33:28 +03:00
|
|
|
start := time.Now()
|
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
|
|
|
if len(msg.Args) < 3 {
|
|
|
|
return NOMessage, errInvalidNumberOfArguments
|
2016-12-12 20:33:28 +03:00
|
|
|
}
|
2018-10-29 01:49:45 +03:00
|
|
|
if len(msg.Args) > 5 {
|
|
|
|
return NOMessage, errInvalidNumberOfArguments
|
2016-12-12 20:33:28 +03:00
|
|
|
}
|
2018-10-29 01:49:45 +03:00
|
|
|
key := msg.Args[1]
|
|
|
|
id := msg.Args[2]
|
2016-12-12 20:33:28 +03:00
|
|
|
var doget bool
|
|
|
|
var path string
|
|
|
|
var raw bool
|
2018-10-29 01:49:45 +03:00
|
|
|
if len(msg.Args) > 3 {
|
2016-12-12 20:33:28 +03:00
|
|
|
doget = true
|
2018-10-29 01:49:45 +03:00
|
|
|
path = msg.Args[3]
|
|
|
|
if len(msg.Args) == 5 {
|
|
|
|
if strings.ToLower(msg.Args[4]) == "raw" {
|
2016-12-12 20:33:28 +03:00
|
|
|
raw = true
|
|
|
|
} else {
|
2018-10-29 01:49:45 +03:00
|
|
|
return NOMessage, errInvalidArgument(msg.Args[4])
|
2016-12-12 20:33:28 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2019-10-30 20:17:59 +03:00
|
|
|
col := s.getCol(key)
|
2016-12-12 20:33:28 +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-12-12 20:33:28 +03:00
|
|
|
}
|
2018-10-29 01:49:45 +03:00
|
|
|
return NOMessage, errKeyNotFound
|
2016-12-12 20:33:28 +03:00
|
|
|
}
|
|
|
|
o, _, ok := col.Get(id)
|
|
|
|
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-12-12 20:33:28 +03:00
|
|
|
}
|
2018-10-29 01:49:45 +03:00
|
|
|
return NOMessage, errIDNotFound
|
2016-12-12 20:33:28 +03:00
|
|
|
}
|
|
|
|
var res gjson.Result
|
|
|
|
if doget {
|
|
|
|
res = gjson.Get(o.String(), path)
|
|
|
|
} else {
|
|
|
|
res = gjson.Parse(o.String())
|
|
|
|
}
|
|
|
|
var val string
|
|
|
|
if raw {
|
|
|
|
val = res.Raw
|
|
|
|
} else {
|
|
|
|
val = res.String()
|
|
|
|
}
|
|
|
|
var buf bytes.Buffer
|
2018-10-29 01:49:45 +03:00
|
|
|
if msg.OutputType == JSON {
|
2016-12-12 20:33:28 +03:00
|
|
|
buf.WriteString(`{"ok":true`)
|
|
|
|
}
|
|
|
|
switch msg.OutputType {
|
2018-10-29 01:49:45 +03:00
|
|
|
case JSON:
|
2016-12-12 20:33:28 +03:00
|
|
|
if res.Exists() {
|
|
|
|
buf.WriteString(`,"value":` + jsonString(val))
|
|
|
|
}
|
|
|
|
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-12-12 20:33:28 +03:00
|
|
|
if !res.Exists() {
|
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-12-12 20:33:28 +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.StringValue(val), nil
|
2016-12-12 20:33:28 +03:00
|
|
|
}
|
2018-10-29 01:49:45 +03:00
|
|
|
return NOMessage, nil
|
2016-12-12 20:33:28 +03:00
|
|
|
}
|
|
|
|
|
2019-10-30 20:17:59 +03:00
|
|
|
func (s *Server) cmdJset(msg *Message) (res resp.Value, d commandDetails, err error) {
|
2016-12-12 20:33:28 +03:00
|
|
|
// JSET key path value [RAW]
|
|
|
|
start := time.Now()
|
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
|
|
|
|
2016-12-12 20:33:28 +03:00
|
|
|
var raw, str bool
|
2018-10-29 01:49:45 +03:00
|
|
|
switch len(msg.Args) {
|
2016-12-12 20:33:28 +03:00
|
|
|
default:
|
2018-10-29 01:49:45 +03:00
|
|
|
return NOMessage, d, errInvalidNumberOfArguments
|
2016-12-12 20:33:28 +03:00
|
|
|
case 5:
|
|
|
|
case 6:
|
2018-10-29 01:49:45 +03:00
|
|
|
switch strings.ToLower(msg.Args[5]) {
|
2016-12-12 20:33:28 +03:00
|
|
|
default:
|
2018-10-29 01:49:45 +03:00
|
|
|
return NOMessage, d, errInvalidArgument(msg.Args[5])
|
2016-12-12 20:33:28 +03:00
|
|
|
case "raw":
|
|
|
|
raw = true
|
|
|
|
case "str":
|
|
|
|
str = true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-10-29 01:49:45 +03:00
|
|
|
key := msg.Args[1]
|
|
|
|
id := msg.Args[2]
|
|
|
|
path := msg.Args[3]
|
|
|
|
val := msg.Args[4]
|
2016-12-12 20:33:28 +03:00
|
|
|
if !str && !raw {
|
|
|
|
switch val {
|
|
|
|
default:
|
2019-10-30 20:17:59 +03:00
|
|
|
raw = isJSONNumber(val)
|
2016-12-12 20:33:28 +03:00
|
|
|
case "true", "false", "null":
|
|
|
|
raw = true
|
|
|
|
}
|
|
|
|
}
|
2019-10-30 20:17:59 +03:00
|
|
|
col := s.getCol(key)
|
2016-12-12 20:33:28 +03:00
|
|
|
var createcol bool
|
|
|
|
if col == nil {
|
|
|
|
col = collection.New()
|
|
|
|
createcol = true
|
|
|
|
}
|
|
|
|
var json string
|
|
|
|
var geoobj bool
|
|
|
|
o, _, ok := col.Get(id)
|
|
|
|
if ok {
|
2018-10-11 00:25:40 +03:00
|
|
|
geoobj = objIsSpatial(o)
|
2016-12-12 20:33:28 +03:00
|
|
|
json = o.String()
|
|
|
|
}
|
|
|
|
if raw {
|
|
|
|
// set as raw block
|
|
|
|
json, err = sjson.SetRaw(json, path, val)
|
|
|
|
} else {
|
|
|
|
// set as a string
|
|
|
|
json, err = sjson.Set(json, path, val)
|
|
|
|
}
|
|
|
|
if err != nil {
|
2018-10-29 01:49:45 +03:00
|
|
|
return NOMessage, d, err
|
2016-12-12 20:33:28 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
if geoobj {
|
|
|
|
nmsg := *msg
|
2018-10-29 01:49:45 +03:00
|
|
|
nmsg.Args = []string{"SET", key, id, "OBJECT", json}
|
2016-12-12 20:33:28 +03:00
|
|
|
// SET key id OBJECT json
|
2019-10-30 20:17:59 +03:00
|
|
|
return s.cmdSet(&nmsg, false)
|
2016-12-12 20:33:28 +03:00
|
|
|
}
|
|
|
|
if createcol {
|
2019-10-30 20:17:59 +03:00
|
|
|
s.setCol(key, col)
|
2016-12-12 20:33:28 +03:00
|
|
|
}
|
2016-12-14 17:37:02 +03:00
|
|
|
|
|
|
|
d.key = key
|
|
|
|
d.id = id
|
2018-10-11 00:25:40 +03:00
|
|
|
d.obj = collection.String(json)
|
2016-12-14 17:37:02 +03:00
|
|
|
d.timestamp = time.Now()
|
|
|
|
d.updated = true
|
|
|
|
|
2019-10-30 20:17:59 +03:00
|
|
|
s.clearIDExpires(key, id)
|
2018-08-16 23:07:55 +03:00
|
|
|
col.Set(d.id, d.obj, nil, nil)
|
2016-12-12 20:33:28 +03:00
|
|
|
switch msg.OutputType {
|
2018-10-29 01:49:45 +03:00
|
|
|
case JSON:
|
2016-12-12 20:33:28 +03:00
|
|
|
var buf bytes.Buffer
|
|
|
|
buf.WriteString(`{"ok":true`)
|
|
|
|
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()), d, 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("OK"), d, nil
|
2016-12-12 20:33:28 +03:00
|
|
|
}
|
2018-10-29 01:49:45 +03:00
|
|
|
return NOMessage, d, nil
|
2016-12-12 20:33:28 +03:00
|
|
|
}
|
|
|
|
|
2019-10-30 20:17:59 +03:00
|
|
|
func (s *Server) cmdJdel(msg *Message) (res resp.Value, d commandDetails, err error) {
|
2016-12-12 20:33:28 +03:00
|
|
|
start := time.Now()
|
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
|
|
|
if len(msg.Args) != 4 {
|
|
|
|
return NOMessage, d, errInvalidNumberOfArguments
|
2016-12-12 20:33:28 +03:00
|
|
|
}
|
2018-10-29 01:49:45 +03:00
|
|
|
key := msg.Args[1]
|
|
|
|
id := msg.Args[2]
|
|
|
|
path := msg.Args[3]
|
2016-12-12 20:33:28 +03:00
|
|
|
|
2019-10-30 20:17:59 +03:00
|
|
|
col := s.getCol(key)
|
2016-12-12 20:33:28 +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.IntegerValue(0), d, nil
|
2016-12-12 20:33:28 +03:00
|
|
|
}
|
2018-10-29 01:49:45 +03:00
|
|
|
return NOMessage, d, errKeyNotFound
|
2016-12-12 20:33:28 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
var json string
|
|
|
|
var geoobj bool
|
|
|
|
o, _, ok := col.Get(id)
|
|
|
|
if ok {
|
2018-10-11 00:25:40 +03:00
|
|
|
geoobj = objIsSpatial(o)
|
2016-12-12 20:33:28 +03:00
|
|
|
json = o.String()
|
|
|
|
}
|
|
|
|
njson, err := sjson.Delete(json, path)
|
|
|
|
if err != nil {
|
2018-10-29 01:49:45 +03:00
|
|
|
return NOMessage, d, err
|
2016-12-12 20:33:28 +03:00
|
|
|
}
|
|
|
|
if njson == json {
|
|
|
|
switch msg.OutputType {
|
2018-10-29 01:49:45 +03:00
|
|
|
case JSON:
|
|
|
|
return NOMessage, d, errPathNotFound
|
|
|
|
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.IntegerValue(0), d, nil
|
2016-12-12 20:33:28 +03:00
|
|
|
}
|
2018-10-29 01:49:45 +03:00
|
|
|
return NOMessage, d, nil
|
2016-12-12 20:33:28 +03:00
|
|
|
}
|
|
|
|
json = njson
|
|
|
|
if geoobj {
|
|
|
|
nmsg := *msg
|
2018-10-29 01:49:45 +03:00
|
|
|
nmsg.Args = []string{"SET", key, id, "OBJECT", json}
|
2016-12-12 20:33:28 +03:00
|
|
|
// SET key id OBJECT json
|
2019-10-30 20:17:59 +03:00
|
|
|
return s.cmdSet(&nmsg, false)
|
2016-12-12 20:33:28 +03:00
|
|
|
}
|
2016-12-14 17:37:02 +03:00
|
|
|
|
|
|
|
d.key = key
|
|
|
|
d.id = id
|
2018-10-11 00:25:40 +03:00
|
|
|
d.obj = collection.String(json)
|
2016-12-14 17:37:02 +03:00
|
|
|
d.timestamp = time.Now()
|
|
|
|
d.updated = true
|
|
|
|
|
2019-10-30 20:17:59 +03:00
|
|
|
s.clearIDExpires(d.key, d.id)
|
2018-08-16 23:07:55 +03:00
|
|
|
col.Set(d.id, d.obj, nil, nil)
|
2016-12-12 20:33:28 +03:00
|
|
|
switch msg.OutputType {
|
2018-10-29 01:49:45 +03:00
|
|
|
case JSON:
|
2016-12-12 20:33:28 +03:00
|
|
|
var buf bytes.Buffer
|
|
|
|
buf.WriteString(`{"ok":true`)
|
|
|
|
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()), d, 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.IntegerValue(1), d, nil
|
2016-12-12 20:33:28 +03:00
|
|
|
}
|
2018-10-29 01:49:45 +03:00
|
|
|
return NOMessage, d, nil
|
2016-12-12 20:33:28 +03:00
|
|
|
}
|