douxing6532 2015-09-05 20:49
浏览 51
已采纳

gob:接口仅在编码上注册,但未在解码上注册

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

  • 写回答

1条回答 默认 最新

  • douba5540 2015-09-06 14:23
    关注

    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.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 有了解d3和topogram.js库的吗?有偿请教
  • ¥100 任意维数的K均值聚类
  • ¥15 stamps做sbas-insar,时序沉降图怎么画
  • ¥15 unity第一人称射击小游戏,有demo,在原脚本的基础上进行修改以达到要求
  • ¥15 买了个传感器,根据商家发的代码和步骤使用但是代码报错了不会改,有没有人可以看看
  • ¥15 关于#Java#的问题,如何解决?
  • ¥15 加热介质是液体,换热器壳侧导热系数和总的导热系数怎么算
  • ¥100 嵌入式系统基于PIC16F882和热敏电阻的数字温度计
  • ¥15 cmd cl 0x000007b
  • ¥20 BAPI_PR_CHANGE how to add account assignment information for service line