
* 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
74 lines
1.8 KiB
Go
74 lines
1.8 KiB
Go
package lua
|
|
|
|
import (
|
|
"reflect"
|
|
"unsafe"
|
|
)
|
|
|
|
// iface is an internal representation of the go-interface.
|
|
type iface struct {
|
|
itab unsafe.Pointer
|
|
word unsafe.Pointer
|
|
}
|
|
|
|
const preloadLimit LNumber = 128
|
|
|
|
var _fv float64
|
|
var _uv uintptr
|
|
|
|
// allocator is a fast bulk memory allocator for the LValue.
|
|
type allocator struct {
|
|
top int
|
|
size int
|
|
nptrs []LValue
|
|
nheader *reflect.SliceHeader
|
|
fptrs []float64
|
|
fheader *reflect.SliceHeader
|
|
itabLNumber unsafe.Pointer
|
|
preloads [int(preloadLimit)]LValue
|
|
}
|
|
|
|
func newAllocator(size int) *allocator {
|
|
al := &allocator{
|
|
top: 0,
|
|
size: size,
|
|
nptrs: make([]LValue, size),
|
|
nheader: nil,
|
|
fptrs: make([]float64, size),
|
|
fheader: nil,
|
|
itabLNumber: unsafe.Pointer(nil),
|
|
}
|
|
al.nheader = (*reflect.SliceHeader)(unsafe.Pointer(&al.nptrs))
|
|
al.fheader = (*reflect.SliceHeader)(unsafe.Pointer(&al.fptrs))
|
|
|
|
var v LValue = LNumber(0)
|
|
vp := (*iface)(unsafe.Pointer(&v))
|
|
al.itabLNumber = vp.itab
|
|
for i := 0; i < int(preloadLimit); i++ {
|
|
al.preloads[i] = LNumber(i)
|
|
}
|
|
return al
|
|
}
|
|
|
|
func (al *allocator) LNumber2I(v LNumber) LValue {
|
|
if v >= 0 && v < preloadLimit && float64(v) == float64(int64(v)) {
|
|
return al.preloads[int(v)]
|
|
}
|
|
if al.top == len(al.nptrs)-1 {
|
|
al.top = 0
|
|
al.nptrs = make([]LValue, al.size)
|
|
al.nheader = (*reflect.SliceHeader)(unsafe.Pointer(&al.nptrs))
|
|
al.fptrs = make([]float64, al.size)
|
|
al.fheader = (*reflect.SliceHeader)(unsafe.Pointer(&al.fptrs))
|
|
}
|
|
fptr := (*float64)(unsafe.Pointer(al.fheader.Data + uintptr(al.top)*unsafe.Sizeof(_fv)))
|
|
e := *(*LValue)(unsafe.Pointer(al.nheader.Data + uintptr(al.top)*unsafe.Sizeof(_uv)))
|
|
al.top++
|
|
|
|
ep := (*iface)(unsafe.Pointer(&e))
|
|
ep.itab = al.itabLNumber
|
|
*fptr = float64(v)
|
|
ep.word = unsafe.Pointer(fptr)
|
|
return e
|
|
}
|