| OLD | NEW |
| (Empty) | |
| 1 // Copyright 2017 The LUCI Authors. All rights reserved. |
| 2 // Use of this source code is governed under the Apache License, Version 2.0 |
| 3 // that can be found in the LICENSE file. |
| 4 |
| 5 package config |
| 6 |
| 7 import ( |
| 8 "context" |
| 9 "time" |
| 10 |
| 11 "github.com/luci/luci-go/common/data/caching/proccache" |
| 12 "github.com/luci/luci-go/common/sync/mutexpool" |
| 13 "github.com/luci/luci-go/luci_config/common/cfgtypes" |
| 14 "github.com/luci/luci-go/luci_config/server/cfgclient" |
| 15 "github.com/luci/luci-go/luci_config/server/cfgclient/textproto" |
| 16 |
| 17 "github.com/golang/protobuf/proto" |
| 18 ) |
| 19 |
| 20 type messageCacheKey struct { |
| 21 cset cfgtypes.ConfigSet |
| 22 path string |
| 23 } |
| 24 |
| 25 // MessageCache is an in-memory configuration cache. Unlike the "MessageCache" c
onfig |
| 26 // Backend, this stores the unmarshaled configuration object in-memory. |
| 27 type MessageCache struct { |
| 28 // Lifetime is the lifetime applied to an individual cache entry. If Lif
etime |
| 29 // is <= 0, no caching will occur. |
| 30 Lifetime time.Duration |
| 31 |
| 32 mutexes mutexpool.P |
| 33 } |
| 34 |
| 35 // Get returns an unmarshalled configuration service text protobuf message. |
| 36 // |
| 37 // If the message is not currently in the process cache, it will be fetched from |
| 38 // the config service and cached prior to being returned. |
| 39 func (pc *MessageCache) Get(c context.Context, cset cfgtypes.ConfigSet, path str
ing, msg proto.Message) ( |
| 40 proto.Message, error) { |
| 41 |
| 42 // If no Lifetime is configured, bypass the cache layer. |
| 43 if pc.Lifetime <= 0 { |
| 44 err := pc.GetUncached(c, cset, path, msg) |
| 45 return msg, err |
| 46 } |
| 47 |
| 48 key := messageCacheKey{cset, path} |
| 49 |
| 50 // Load the value from our cache. First, though, take out a lock on this |
| 51 // specific config key. This will prevent multiple concurrent accesses f
rom |
| 52 // slamming the config service, particularly at startup. |
| 53 var v interface{} |
| 54 var err error |
| 55 pc.mutexes.WithMutex(key, func() { |
| 56 v, err = proccache.GetOrMake(c, key, func() (interface{}, time.D
uration, error) { |
| 57 // Not in cache or expired. Reload... |
| 58 if err := pc.GetUncached(c, cset, path, msg); err != nil
{ |
| 59 return nil, 0, err |
| 60 } |
| 61 return msg, pc.Lifetime, nil |
| 62 }) |
| 63 }) |
| 64 |
| 65 if err != nil { |
| 66 return nil, err |
| 67 } |
| 68 return v.(proto.Message), nil |
| 69 } |
| 70 |
| 71 // GetUncached returns an unmarshalled configuration service text protobuf |
| 72 // message. This bypasses the cache, and, on success, does not cache the |
| 73 // resulting value. |
| 74 func (pc *MessageCache) GetUncached(c context.Context, cset cfgtypes.ConfigSet,
path string, |
| 75 msg proto.Message) error { |
| 76 |
| 77 return cfgclient.Get(c, cfgclient.AsService, cset, path, textproto.Messa
ge(msg), nil) |
| 78 } |
| OLD | NEW |