OLD | NEW |
(Empty) | |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 package dscache |
| 6 |
| 7 import ( |
| 8 "sync" |
| 9 "time" |
| 10 |
| 11 "github.com/luci/gae/service/datastore" |
| 12 "github.com/luci/gae/service/info" |
| 13 "github.com/luci/gae/service/memcache" |
| 14 "github.com/luci/luci-go/common/clock" |
| 15 "golang.org/x/net/context" |
| 16 ) |
| 17 |
| 18 type GlobalConfig struct { |
| 19 _id int64 `gae:"$id,1"` |
| 20 _kind string `gae:"$kind,dscache"` |
| 21 |
| 22 Enable bool |
| 23 } |
| 24 |
| 25 var ( |
| 26 globalEnabledLock = sync.RWMutex{} |
| 27 |
| 28 // globalEnabled is whether or not memcache has been globally enabled. I
t is |
| 29 // populated by IsGloballyEnabled when SetGlobalEnable has been set to |
| 30 // true. |
| 31 globalEnabled = true |
| 32 |
| 33 // globalEnabledNextCheck is IsGloballyEnabled's last successful check o
f the |
| 34 // global disable key. |
| 35 globalEnabledNextCheck = time.Time{} |
| 36 ) |
| 37 |
| 38 // IsGloballyEnabled checks to see if this filter is enabled globally. |
| 39 // |
| 40 // This checks InstanceEnabledStatic, as well as polls the datastore entity |
| 41 // /dscache,1 (a GlobalConfig instance) |
| 42 // Once every GlobalEnabledCheckInterval. |
| 43 // |
| 44 // For correctness, any error encountered returns true. If this assumed false, |
| 45 // then Put operations might incorrectly invalidate the cache. |
| 46 func IsGloballyEnabled(c context.Context) bool { |
| 47 if !InstanceEnabledStatic { |
| 48 return false |
| 49 } |
| 50 |
| 51 now := clock.Now(c) |
| 52 |
| 53 globalEnabledLock.RLock() |
| 54 nextCheck := globalEnabledNextCheck |
| 55 enabledVal := globalEnabled |
| 56 globalEnabledLock.RUnlock() |
| 57 |
| 58 if now.Before(nextCheck) { |
| 59 return enabledVal |
| 60 } |
| 61 |
| 62 globalEnabledLock.Lock() |
| 63 defer globalEnabledLock.Unlock() |
| 64 // just in case we raced |
| 65 if now.Before(globalEnabledNextCheck) { |
| 66 return globalEnabled |
| 67 } |
| 68 |
| 69 // always go to the default namespace |
| 70 c, err := info.Get(c).Namespace("") |
| 71 if err != nil { |
| 72 return true |
| 73 } |
| 74 cfg := &GlobalConfig{Enable: true} |
| 75 if err := datastore.Get(c).Get(cfg); err != nil && err != datastore.ErrN
oSuchEntity { |
| 76 return true |
| 77 } |
| 78 globalEnabled = cfg.Enable |
| 79 globalEnabledNextCheck = now.Add(GlobalEnabledCheckInterval) |
| 80 return globalEnabled |
| 81 } |
| 82 |
| 83 func SetGlobalEnable(c context.Context, memcacheEnabled bool) error { |
| 84 // always go to the default namespace |
| 85 c, err := info.Get(c).Namespace("") |
| 86 if err != nil { |
| 87 return err |
| 88 } |
| 89 return datastore.Get(c).RunInTransaction(func(c context.Context) error { |
| 90 ds := datastore.Get(c) |
| 91 cfg := &GlobalConfig{Enable: true} |
| 92 if err := ds.Get(cfg); err != nil && err != datastore.ErrNoSuchE
ntity { |
| 93 return err |
| 94 } |
| 95 if cfg.Enable == memcacheEnabled { |
| 96 return nil |
| 97 } |
| 98 cfg.Enable = memcacheEnabled |
| 99 if memcacheEnabled { |
| 100 // when going false -> true, wipe memcache. |
| 101 if err := memcache.Get(c).Flush(); err != nil { |
| 102 return err |
| 103 } |
| 104 } |
| 105 return ds.Put(cfg) |
| 106 }, nil) |
| 107 } |
OLD | NEW |