简体   繁体   中英

gob: interface is only registered on Encode but not on Decode

I'm working on an appengine app using the datastore. I'm attempting to gob encode an interface and store it into the datastore. But when I try to load from the datastore, I get the error:

gob: name not registered for interface: "main27155.strand"

The peculiar thing is that the load() method starts working after having called the save() method. It no longer returns an error, and everything saved in the datastore is loaded as expected. But when I restart the intance, the load() method stops working again.

The load and save methods I mention refer to the methods defined by the datastore.PropertyLoadSaver interface

From the looks of it, it seems like a problem with registering the type/interfaces with gob, but I have exactly the same gob.Register() calls in both the load() and save() methods.

I even tried removing the gob.Register() calls from both load and save methods and adding it to init() . The exact same behavior was observed.

How can I load my datastore on a cold start?

type bio struct {¬                          
    Id       string¬                        
    Hp       int¬                           
    godie    chan bool //should be buffered¬
    dam      chan int¬                      
    Genetics dna¬                           
}¬                                          

type dna interface {
    decode() mRNA
    Get(int) trait
    Set(int, trait)
    Duplicate() dna
    Len() int
}
type trait interface {
    mutate() trait
}

// implements dna{}
type strand []trait

// implements trait{}
type tdecoration string
type color struct {
    None bool // If true, colors are not shown in theme
    Bg   bool // If true, color is a background color
    R    int  // 0-255
    G    int
    B    int
}

.

func start(w http.ResponseWriter, r *http.Request) error {
    c := appengine.NewContext(r)

    var bs []bio
    if _, err := datastore.NewQuery("bio").GetAll(c, &bs); err != nil {
        log.Println("bs is len: ", len(bs))
        return err
    }

    ...
    return nil
}

func stop(w http.ResponseWriter, r *http.Request) error {
    c := appengine.NewContext(r)
    log.Println("Saving top 20 colors")
    var k []*datastore.Key
    var bs []*bio
    stat := getStats()
    for i, b := range stat.Leaderboard {
        k = append(k, datastore.NewKey(c, "bio", b.Id, 0, nil))
        bv := b
        bs = append(bs, &bv)
        // At most 20 bios survive across reboots
        if i > 178 {
            break
        }
    }

    // Assemble slice of keys for deletion
    dk, err := datastore.NewQuery("bio").KeysOnly().GetAll(c, nil)
    if err != nil {
        return errors.New(fmt.Sprintf("Query error: %s", err.Error()))
    }

    fn := func(c appengine.Context) error {
        // Delete all old entries
        err := datastore.DeleteMulti(c, dk)
        if err != nil {
            return errors.New(fmt.Sprintf("Delete error: %s", err.Error()))
        }

        // save the elite in the datastore
        _, err = datastore.PutMulti(c, k, bs)
        if err != nil {
            return err
        }
        return nil
    }

    return datastore.RunInTransaction(c, fn, &datastore.TransactionOptions{XG: true})
}

// satisfy datastore PropertyLoadSaver interface ===============================

func (b *bio) Load(c <-chan datastore.Property) error {
    gob.Register(&color{})
    gob.Register(new(tdecoration))
    var str strand
    gob.Register(str)

    tmp := struct {
        Id     string
        Hp     int
        Gengob []byte
    }{}
    if err := datastore.LoadStruct(&tmp, c); err != nil {
        return err
    }

    b.Id = tmp.Id
    b.Hp = tmp.Hp

    return gob.NewDecoder(strings.NewReader(string(tmp.Gengob))).Decode(&(b.Genetics))
}
func (b *bio) Save(c chan<- datastore.Property) error {
    defer close(c)
    gob.Register(&color{})
    gob.Register(new(tdecoration))
    var str strand
    gob.Register(str)

    var buf bytes.Buffer
    gen := b.Genetics
    if err := gob.NewEncoder(&buf).Encode(&gen); err != nil {
        log.Println(err)
        return err
    }
    dp := []datastore.Property{
        {Name: "Id", Value: b.Id},
        {Name: "Hp", Value: int64(b.Hp)},
        {Name: "Gengob", Value: buf.Bytes(), NoIndex: true},
    }
    for _, p := range dp {
        c <- p
    }
    return nil
}

Additional info: This behavior was not present before I stuffed the datastore calls in stop() into datastore.RunInTransaction()

Register all types an in init() functions using RegisterName() . Delete all existing data from the store and you should be good to go.

App Engine generates a mangled name for the main package every time the application is built. The name generated by Register() includes this mangled package name. Any gobs encoded with the mangled name will only be readable using the same build of the app. If you cause the application to be rebuilt by modifying the code, then the app will not be able to decode gobs stored previously.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM