Last active
October 28, 2021 06:18
-
-
Save imjasonh/e846785003b0509be05f to your computer and use it in GitHub Desktop.
appengine datastore/memcache wrapper
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// TODO: support for *Multi methods, with special care about handling MultiErrors | |
// TODO: support for Query, which mostly depends on serializing Query structs | |
// TODO: support for (or at least intelligently ignore) PropertyLoadSavers | |
// TODO: tests? | |
// TODO: benchmarks? | |
package dsmem | |
import ( | |
"errors" | |
"time" | |
"appengine" | |
"appengine/datastore" | |
"appengine/memcache" | |
) | |
var ( | |
// Codec is the codec to use to serialize entities when caching. | |
// By default, this uses gob encoding. | |
Codec = memcache.Gob | |
// Expiration is the amount of time that cached entities should be kept. | |
// By default, there is no expiration. | |
Expiration time.Duration | |
// ErrInconsistentCache is the error that is returned by operations that would | |
// leave the cache in an inconsistent state with the datastore. | |
ErrInconsistentCache = errors.New("invalid cache state") | |
) | |
func Get(ctx appengine.Context, key *datastore.Key, dst interface{}) error { | |
if _, err := Codec.Get(ctx, key.Encode(), dst); err != nil { | |
// TODO: what if err != ErrCacheMiss? log something? | |
return datastore.Get(ctx, key, dst) | |
} | |
return nil | |
} | |
func Put(ctx appengine.Context, key *datastore.Key, src interface{}) (*datastore.Key, error) { | |
if err := Codec.Set(ctx, &memcache.Item{ | |
Key: key.Encode(), | |
Object: src, | |
Expiration: Expiration, | |
}); err != nil { | |
// If we can't update the cache, at least try to make sure we don't cache inconsistently. | |
// If invalidating the cache fails, fail the entire operation. | |
if err := memcache.Delete(ctx, key.Encode()); err != nil && err != memcache.ErrCacheMiss { | |
return nil, ErrInconsistentCache | |
} | |
} | |
return datastore.Put(ctx, key, src) | |
} | |
func Delete(ctx appengine.Context, key *datastore.Key) error { | |
if err := memcache.Delete(ctx, key.Encode()); err != nil && err != memcache.ErrCacheMiss { | |
// If we can't remove the item from the cache, fail the entire operation. | |
return ErrInconsistentCache | |
} | |
return datastore.Delete(ctx, key) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment