| OLD | NEW |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 // Package settings implements storage for infrequently changing global | 5 // Package settings implements storage for infrequently changing global |
| 6 // settings. | 6 // settings. |
| 7 // | 7 // |
| 8 // Settings are represented as (key, value) pairs, where value is JSON | 8 // Settings are represented as (key, value) pairs, where value is JSON |
| 9 // serializable struct. Settings are cached internally in the process memory to | 9 // serializable struct. Settings are cached internally in the process memory to |
| 10 // avoid hitting the storage all the time. | 10 // avoid hitting the storage all the time. |
| 11 package settings | 11 package settings |
| 12 | 12 |
| 13 import ( | 13 import ( |
| 14 "encoding/json" | 14 "encoding/json" |
| 15 "errors" | 15 "errors" |
| 16 "reflect" | 16 "reflect" |
| 17 "sync" | 17 "sync" |
| 18 "time" | 18 "time" |
| 19 | 19 |
| 20 "golang.org/x/net/context" | 20 "golang.org/x/net/context" |
| 21 | 21 |
| 22 "github.com/luci/luci-go/common/clock" |
| 22 "github.com/luci/luci-go/common/lazyslot" | 23 "github.com/luci/luci-go/common/lazyslot" |
| 24 "github.com/luci/luci-go/common/retry" |
| 23 ) | 25 ) |
| 24 | 26 |
| 25 var ( | 27 var ( |
| 26 // ErrNoSettings can be returned by Get and Set on fatal errors. | 28 // ErrNoSettings can be returned by Get and Set on fatal errors. |
| 27 ErrNoSettings = errors.New("settings: settings are not available") | 29 ErrNoSettings = errors.New("settings: settings are not available") |
| 28 | 30 |
| 29 // ErrBadType is returned if Get(...) receives unexpected type. | 31 // ErrBadType is returned if Get(...) receives unexpected type. |
| 30 ErrBadType = errors.New("settings: bad type") | 32 ErrBadType = errors.New("settings: bad type") |
| 31 ) | 33 ) |
| 32 | 34 |
| (...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 109 storage Storage // used to load and save settings | 111 storage Storage // used to load and save settings |
| 110 values lazyslot.Slot // cached settings | 112 values lazyslot.Slot // cached settings |
| 111 } | 113 } |
| 112 | 114 |
| 113 // New creates new Settings object that uses given Storage to fetch and save | 115 // New creates new Settings object that uses given Storage to fetch and save |
| 114 // settings. | 116 // settings. |
| 115 func New(storage Storage) *Settings { | 117 func New(storage Storage) *Settings { |
| 116 return &Settings{ | 118 return &Settings{ |
| 117 storage: storage, | 119 storage: storage, |
| 118 values: lazyslot.Slot{ | 120 values: lazyslot.Slot{ |
| 119 » » » Fetcher: func(c context.Context, _ lazyslot.Value) (lazy
slot.Value, error) { | 121 » » » Timeout: 15 * time.Second, // retry for 15 sec at most |
| 120 » » » » bundle, err := storage.FetchAllSettings(c) | 122 » » » Fetcher: func(c context.Context, _ lazyslot.Value) (resu
lt lazyslot.Value, err error) { |
| 123 » » » » err = retry.Retry(c, retry.TransientOnly(retry.D
efault), func() error { |
| 124 » » » » » ctx, _ := clock.WithTimeout(c, 2*time.Se
cond) // trigger a retry after 2 sec RPC timeout |
| 125 » » » » » result, err = attemptToFetchSettings(ctx
, storage) |
| 126 » » » » » return err |
| 127 » » » » }, nil) |
| 121 if err != nil { | 128 if err != nil { |
| 122 » » » » » return lazyslot.Value{}, err | 129 » » » » » result = lazyslot.Value{} |
| 123 } | 130 } |
| 124 » » » » return lazyslot.Value{ | 131 » » » » return |
| 125 » » » » » Value: bundle, | |
| 126 » » » » » Expiration: bundle.Exp, | |
| 127 » » » » }, nil | |
| 128 }, | 132 }, |
| 129 }, | 133 }, |
| 130 } | 134 } |
| 131 } | 135 } |
| 132 | 136 |
| 137 // attemptToFetchSettings is called in a retry loop when loading settings. |
| 138 func attemptToFetchSettings(c context.Context, storage Storage) (lazyslot.Value,
error) { |
| 139 bundle, err := storage.FetchAllSettings(c) |
| 140 if err != nil { |
| 141 return lazyslot.Value{}, err |
| 142 } |
| 143 return lazyslot.Value{ |
| 144 Value: bundle, |
| 145 Expiration: bundle.Exp, |
| 146 }, nil |
| 147 } |
| 148 |
| 133 // GetStorage returns underlying Storage instance. | 149 // GetStorage returns underlying Storage instance. |
| 134 func (s *Settings) GetStorage() Storage { | 150 func (s *Settings) GetStorage() Storage { |
| 135 return s.storage | 151 return s.storage |
| 136 } | 152 } |
| 137 | 153 |
| 138 // Get returns setting value (possibly cached) for the given key. | 154 // Get returns setting value (possibly cached) for the given key. |
| 139 // | 155 // |
| 140 // It will be deserialized into the supplied value. Caller is responsible | 156 // It will be deserialized into the supplied value. Caller is responsible |
| 141 // to pass correct type and pass same type to all calls. If the setting is not | 157 // to pass correct type and pass same type to all calls. If the setting is not |
| 142 // set returns ErrNoSettings. | 158 // set returns ErrNoSettings. |
| (...skipping 21 matching lines...) Expand all Loading... |
| 164 // | 180 // |
| 165 // New settings will apply only when existing in-memory cache expires. | 181 // New settings will apply only when existing in-memory cache expires. |
| 166 // In particular, Get() right after Set() may still return old value. | 182 // In particular, Get() right after Set() may still return old value. |
| 167 func (s *Settings) Set(c context.Context, key string, value interface{}, who, wh
y string) error { | 183 func (s *Settings) Set(c context.Context, key string, value interface{}, who, wh
y string) error { |
| 168 blob, err := json.Marshal(value) | 184 blob, err := json.Marshal(value) |
| 169 if err != nil { | 185 if err != nil { |
| 170 return err | 186 return err |
| 171 } | 187 } |
| 172 return s.storage.UpdateSetting(c, key, json.RawMessage(blob), who, why) | 188 return s.storage.UpdateSetting(c, key, json.RawMessage(blob), who, why) |
| 173 } | 189 } |
| OLD | NEW |