valyala / ybc

Fast in-process BLOB cache with persistence support
https://groups.google.com/forum/?fromgroups=#!forum/ybc-main
Other
401 stars 43 forks source link

Cant store json in ybc using golang #14

Open vektah opened 8 years ago

vektah commented 8 years ago

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 8 years ago

This looks like a bug in Go runtime. Will try narrowing down it and posting to Go issue tracker.

valyala commented 8 years ago

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 8 years ago

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 8 years ago

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)
}