Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(289)

Side by Side Diff: appengine/gaeconfig/cache.go

Issue 2575383002: Add server/cache support to gaeconfig. (Closed)
Patch Set: Created 4 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | appengine/gaeconfig/cache_test.go » ('j') | appengine/gaeconfig/default.go » ('J')
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2015 The LUCI Authors. All rights reserved. 1 // Copyright 2015 The LUCI Authors. All rights reserved.
2 // Use of this source code is governed under the Apache License, Version 2.0 2 // Use of this source code is governed under the Apache License, Version 2.0
3 // that can be found in the LICENSE file. 3 // that can be found in the LICENSE file.
4 4
5 package gaeconfig 5 package gaeconfig
iannucci 2017/01/07 21:05:26 this package could be split into luci-config/cachi
dnj 2017/01/10 03:30:07 Sure, done.
6 6
7 import ( 7 import (
8 » "bytes" 8 » "encoding/hex"
9 » "encoding/binary"
10 » "fmt"
11 "time" 9 "time"
12 10
13 ds "github.com/luci/gae/service/datastore"
14 mc "github.com/luci/gae/service/memcache" 11 mc "github.com/luci/gae/service/memcache"
15 » "github.com/luci/luci-go/common/clock" 12 » "github.com/luci/luci-go/common/errors"
16 » "github.com/luci/luci-go/common/config"
17 » "github.com/luci/luci-go/common/config/filters/caching"
18 » "github.com/luci/luci-go/common/data/caching/proccache"
19 log "github.com/luci/luci-go/common/logging" 13 log "github.com/luci/luci-go/common/logging"
14 "github.com/luci/luci-go/server/config"
15 "github.com/luci/luci-go/server/config/caching"
20 16
21 "golang.org/x/net/context" 17 "golang.org/x/net/context"
22 ) 18 )
23 19
24 // WrapWithCache wraps config client with proccache-and-memcache-caching layer. 20 const (
25 func WrapWithCache(cfg config.Interface, expire time.Duration) config.Interface { 21 » memCacheSchema = "v1"
26 » return caching.Wrap(cfg, caching.Options{ 22 » maxMemCacheSize = 1024 * 1024 // 1MB
27 » » Cache: &cache{}, 23 )
28 » » Expiration: expire,
29 » })
30 }
31 24
32 type cache struct{} 25 func memcacheBackend(b config.Backend, exp time.Duration) config.Backend {
26 » return &caching.Backend{
27 » » Backend: b,
28 » » CacheGet: func(c context.Context, key caching.Key, l caching.Loa der) (*caching.Value, error) {
29 » » » if key.Authority != config.AsService {
30 » » » » return l(c, key, nil)
31 » » » }
33 32
34 type proccacheKey string 33 » » » // Is the item already cached?
34 » » » k := memcacheKey(&key)
35 » » » mci, err := mc.GetKey(c, k)
36 » » » switch err {
37 » » » case nil:
38 » » » » // Value was cached, successfully retrieved.
39 » » » » v, err := caching.DecodeValue(mci.Value())
40 » » » » if err != nil {
41 » » » » » return nil, errors.Annotate(err).Reason( "failed to decode cache value from %(key)q").
42 » » » » » » D("key", k).Err()
43 » » » » }
44 » » » » return v, nil
35 45
36 func (c *cache) Store(ctx context.Context, baseKey string, expire time.Duration, value []byte) { 46 » » » case mc.ErrCacheMiss:
37 » k := cacheKey(baseKey) 47 » » » » // Value was not cached. Load from Loader and ca che.
48 » » » » v, err := l(c, key, nil)
49 » » » » if err != nil {
50 » » » » » return nil, err
51 » » » » }
38 52
39 » proccache.Put(ctx, k, value, expire) 53 » » » » // Attempt to cache the value. If this fails, we 'll log a warning and
54 » » » » // move on.
55 » » » » err = func() error {
56 » » » » » d, err := v.Encode()
57 » » » » » if err != nil {
58 » » » » » » return errors.Annotate(err).Reas on("failed to encode value").Err()
59 » » » » » }
40 60
41 » // value in memcache is [varint(expiration_ts.Millis) ++ value] 61 » » » » » if len(d) > maxMemCacheSize {
42 » // value in proccache is [value] 62 » » » » » » return errors.Reason("entry exce eds memcache size (%(size)d > %(max)d)").
iannucci 2017/01/07 21:05:26 should this be logged instead of an error?
dnj 2017/01/10 03:30:07 I don't think so. If config entries are really big
43 » // 63 » » » » » » » D("size", len(d)).D("max ", maxMemCacheSize).Err()
44 » // This is because memcache doesn't populate the .Expiration field of th e 64 » » » » » }
45 » // memcache Item on Get operations :(
46 » stamp := ds.TimeToInt(clock.Now(ctx).UTC().Add(expire))
47 » buf := make([]byte, binary.MaxVarintLen64)
48 » value = append(buf[:binary.PutVarint(buf, stamp)], value...)
49 65
50 » itm := mc.NewItem(ctx, string(k)).SetExpiration(expire).SetValue(value) 66 » » » » » item := mc.NewItem(c, k).SetValue(d).Set Expiration(exp)
51 » if err := mc.Set(ctx, itm); err != nil { 67 » » » » » if err := mc.Set(c, item); err != nil {
52 » » log.Fields{ 68 » » » » » » return errors.Annotate(err).Err( )
53 » » » log.ErrorKey: err, 69 » » » » » }
54 » » » "key": baseKey, 70 » » » » » return nil
55 » » » "expire": expire, 71 » » » » }()
56 » » }.Warningf(ctx, "Failed to store cache value.") 72 » » » » if err != nil {
73 » » » » » log.Fields{
74 » » » » » » log.ErrorKey: err,
75 » » » » » » "key": k,
76 » » » » » }.Warningf(c, "Failed to cache config.")
77 » » » » }
78
79 » » » » // Return the loaded value.
80 » » » » return v, nil
81
82 » » » default:
83 » » » » // Unknown memcache error.
84 » » » » log.Fields{
85 » » » » » log.ErrorKey: err,
86 » » » » » "key": k,
87 » » » » }.Warningf(c, "Failed to decode memcached config .")
88 » » » » return l(c, key, nil)
89 » » » }
90 » » },
57 } 91 }
58 } 92 }
59 93
60 func (c *cache) Retrieve(ctx context.Context, baseKey string) []byte { 94 func memcacheKey(key *caching.Key) string { return hex.EncodeToString(key.ParamH ash()) }
61 » k := cacheKey(baseKey)
62 » ret, err := proccache.GetOrMake(ctx, k, func() (value interface{}, exp t ime.Duration, err error) {
63 » » item, err := mc.GetKey(ctx, string(k))
64 » » if err != nil {
65 » » » if err != mc.ErrCacheMiss {
66 » » » » log.Fields{
67 » » » » » log.ErrorKey: err,
68 » » » » » "key": baseKey,
69 » » » » }.Warningf(ctx, "Failed to retrieve memcache val ue.")
70 » » » }
71 » » » return
72 » » }
73
74 » » buf := bytes.NewBuffer(item.Value())
75 » » expStamp, err := binary.ReadVarint(buf)
76 » » if err != nil {
77 » » » log.Fields{
78 » » » » log.ErrorKey: err,
79 » » » » "key": baseKey,
80 » » » }.Warningf(ctx, "Failed to decode stamp in memcache valu e.")
81 » » » return
82 » » }
83
84 » » // proccache will ignore this value if exp is in the past
85 » » exp = ds.IntToTime(expStamp).Sub(clock.Now(ctx))
86 » » value = buf.Bytes()
87 » » return
88 » })
89 » if err != nil {
90 » » return nil
91 » }
92 » return ret.([]byte)
93 }
94
95 func cacheKey(baseKey string) proccacheKey {
96 » return proccacheKey(fmt.Sprintf("luci-config:v2:%s", baseKey))
97 }
OLDNEW
« no previous file with comments | « no previous file | appengine/gaeconfig/cache_test.go » ('j') | appengine/gaeconfig/default.go » ('J')

Powered by Google App Engine
This is Rietveld 408576698