Cant store json in ybc using golang
vektah opened this issue · 4 comments
vektah commented
Not sure what is going on here...
package main
import (
"encoding/json"
"github.com/valyala/ybc/bindings/go/ybc"
"time"
)
func main() {
cfg := &ybc.Config{
DataFileSize: ybc.SizeT(10240),
MaxItemsCount: ybc.SizeT(100),
IndexFile: "foo.idx",
DataFile: "foo.dat",
}
cache, err := cfg.OpenCache(true)
if err != nil {
panic(err)
}
b, err := json.Marshal(123)
if err != nil {
panic(err)
}
if err = cache.Set([]byte("key"), b, time.Hour); err != nil {
panic(err)
}
}
gives
[adam@scopuli ~]$ go run test.go
panic: runtime error: cgo argument has Go pointer to Go pointer
goroutine 1 [running]:
panic(0x5123a0, 0xc82000a430)
/usr/lib/go/src/runtime/panic.go:464 +0x3e6
github.com/valyala/ybc/bindings/go/ybc.(*Cache).Set(0xc82000e2e0, 0xc82000a410, 0x3, 0x8, 0xc820082024, 0x3, 0x40, 0x34630b8a000, 0x0, 0x0)
/home/adam/go/src/github.com/valyala/ybc/bindings/go/ybc/ybc.go:457 +0x385
main.main()
/home/adam/test.go:26 +0x226
exit status 2
However, this works fine:
cache.Set([]byte("key"), []byte(string(b)), time.Hour);
Running:
go version go1.6 linux/amd64
and ybc 82bc72dc617945514a43056c92c023f65e045ae6
valyala commented
This looks like a bug in Go runtime. Will try narrowing down it and posting to Go issue tracker.
valyala commented
As a temporary workaround you can use GODEBUG="cgocheck=0"
environment variable for disabling cgo check. See Environment Variables
chapter in runtime package for details.
valyala commented
Minimized it to:
package main
// static void foo(void *p) {}
import "C"
import (
"encoding/json"
"unsafe"
)
func main() {
b, err := json.Marshal(123)
if err != nil {
panic(err)
}
p := unsafe.Pointer(&b[0])
C.foo(p)
}
valyala commented
There is another workaround mentioned in the linked Go issue:
What is messing up is that encoding/json uses a 64 byte buffer in a larger struct, and if the encoding requires 64 bytes or fewer than the resulting pointer is into that struct. So one workaround is
if len(b) <= 64 {
b = append([]byte(nil), b...)
}
if err = cache.Set([]byte("key"), b, time.Hour); err != nil {
panic(err)
}