Do not register types with encoding/gob
Registering the same type multiple times can lead to a panic. While the panic is handled in Save, the handling prevents saving the cache. While doing this seems like a good idea (since then the caller wouldn't have to register the types themselves), the need to deal with duplicate entries causes issues with Load. If calling Load to initialize a cache right after startup, encoding/gob will have no information about the types written in the cache, and thus won't be able to load the cache. There are also issues w.r.t. how the type is registered in gob, and if they are registered in a different form inside go-cache than they were outside, a panic happens due to different paths being generated: https://github.com/golang/go/blob/master/src/encoding/gob/type.go#L857 Make sure that it's the caller's respansibility to register types with encoding/gob, to avoid issues with gob's Register and so that they can both Save and Load without having to Save beforehand in the same instance.
This commit is contained in:
parent
7d1d6d6ae9
commit
abe7c4fb56
20
cache.go
20
cache.go
|
@ -869,24 +869,22 @@ func (c *cache) DeleteExpired() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write the cache's items (using Gob) to an io.Writer.
|
// Write the cache's items (using Gob) to an io.Writer.
|
||||||
|
//
|
||||||
|
// The caller should register any custom types with encoding/gob.Register
|
||||||
|
// before calling this function.
|
||||||
func (c *cache) Save(w io.Writer) (err error) {
|
func (c *cache) Save(w io.Writer) (err error) {
|
||||||
enc := gob.NewEncoder(w)
|
enc := gob.NewEncoder(w)
|
||||||
defer func() {
|
|
||||||
if x := recover(); x != nil {
|
|
||||||
err = fmt.Errorf("Error registering item types with Gob library")
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
c.RLock()
|
c.RLock()
|
||||||
defer c.RUnlock()
|
defer c.RUnlock()
|
||||||
for _, v := range c.items {
|
|
||||||
gob.Register(v.Object)
|
|
||||||
}
|
|
||||||
err = enc.Encode(&c.items)
|
err = enc.Encode(&c.items)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Save the cache's items to the given filename, creating the file if it
|
// Save the cache's items to the given filename, creating the file if it
|
||||||
// doesn't exist, and overwriting it if it does.
|
// doesn't exist, and overwriting it if it does.
|
||||||
|
//
|
||||||
|
// The caller should register any custom types with encoding/gob.Register
|
||||||
|
// before calling this function.
|
||||||
func (c *cache) SaveFile(fname string) error {
|
func (c *cache) SaveFile(fname string) error {
|
||||||
fp, err := os.Create(fname)
|
fp, err := os.Create(fname)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -902,6 +900,9 @@ func (c *cache) SaveFile(fname string) error {
|
||||||
|
|
||||||
// Add (Gob-serialized) cache items from an io.Reader, excluding any items with
|
// Add (Gob-serialized) cache items from an io.Reader, excluding any items with
|
||||||
// keys that already exist (and haven't expired) in the current cache.
|
// keys that already exist (and haven't expired) in the current cache.
|
||||||
|
//
|
||||||
|
// The caller should register any custom types with encoding/gob.Register
|
||||||
|
// before calling this function.
|
||||||
func (c *cache) Load(r io.Reader) error {
|
func (c *cache) Load(r io.Reader) error {
|
||||||
dec := gob.NewDecoder(r)
|
dec := gob.NewDecoder(r)
|
||||||
items := map[string]*Item{}
|
items := map[string]*Item{}
|
||||||
|
@ -921,6 +922,9 @@ func (c *cache) Load(r io.Reader) error {
|
||||||
|
|
||||||
// Load and add cache items from the given filename, excluding any items with
|
// Load and add cache items from the given filename, excluding any items with
|
||||||
// keys that already exist in the current cache.
|
// keys that already exist in the current cache.
|
||||||
|
//
|
||||||
|
// The caller should register any custom types with encoding/gob.Register
|
||||||
|
// before calling this function.
|
||||||
func (c *cache) LoadFile(fname string) error {
|
func (c *cache) LoadFile(fname string) error {
|
||||||
fp, err := os.Open(fname)
|
fp, err := os.Open(fname)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
Loading…
Reference in New Issue