OLD | NEW |
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 gaesettings implements settings.Storage interface on top of GAE | 5 // Package gaesettings implements settings.Storage interface on top of GAE |
6 // datastore. | 6 // datastore. |
7 // | 7 // |
8 // See github.com/luci/luci-go/server/settings for more details. | 8 // See github.com/luci/luci-go/server/settings for more details. |
9 package gaesettings | 9 package gaesettings |
10 | 10 |
11 import ( | 11 import ( |
12 "encoding/json" | 12 "encoding/json" |
13 "strconv" | 13 "strconv" |
14 "time" | 14 "time" |
15 | 15 |
16 "golang.org/x/net/context" | 16 "golang.org/x/net/context" |
17 | 17 |
18 ds "github.com/luci/gae/service/datastore" | 18 ds "github.com/luci/gae/service/datastore" |
19 "github.com/luci/gae/service/info" | 19 "github.com/luci/gae/service/info" |
20 "github.com/luci/luci-go/common/clock" | 20 "github.com/luci/luci-go/common/clock" |
21 "github.com/luci/luci-go/common/errors" | |
22 "github.com/luci/luci-go/common/logging" | 21 "github.com/luci/luci-go/common/logging" |
| 22 "github.com/luci/luci-go/common/retry" |
23 "github.com/luci/luci-go/server/settings" | 23 "github.com/luci/luci-go/server/settings" |
24 ) | 24 ) |
25 | 25 |
26 // Storage knows how to store JSON blobs with settings in the datastore. | 26 // Storage knows how to store JSON blobs with settings in the datastore. |
27 // | 27 // |
28 // It implements server/settings.EventualConsistentStorage interface. | 28 // It implements server/settings.EventualConsistentStorage interface. |
29 type Storage struct{} | 29 type Storage struct{} |
30 | 30 |
31 // settingsEntity is used to store all settings as JSON blob. Latest settings | 31 // settingsEntity is used to store all settings as JSON blob. Latest settings |
32 // are stored under key (gaesettings.Settings, latest). The historical log is | 32 // are stored under key (gaesettings.Settings, latest). The historical log is |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
74 // FetchAllSettings fetches all latest settings at once. | 74 // FetchAllSettings fetches all latest settings at once. |
75 func (s Storage) FetchAllSettings(c context.Context) (*settings.Bundle, error) { | 75 func (s Storage) FetchAllSettings(c context.Context) (*settings.Bundle, error) { |
76 c = defaultContext(c) | 76 c = defaultContext(c) |
77 logging.Debugf(c, "Fetching app settings from the datastore") | 77 logging.Debugf(c, "Fetching app settings from the datastore") |
78 | 78 |
79 latest := latestSettings() | 79 latest := latestSettings() |
80 switch err := ds.Get(c, &latest); { | 80 switch err := ds.Get(c, &latest); { |
81 case err == ds.ErrNoSuchEntity: | 81 case err == ds.ErrNoSuchEntity: |
82 break | 82 break |
83 case err != nil: | 83 case err != nil: |
84 » » return nil, errors.WrapTransient(err) | 84 » » return nil, retry.Tag.Apply(err) |
85 } | 85 } |
86 | 86 |
87 pairs := map[string]*json.RawMessage{} | 87 pairs := map[string]*json.RawMessage{} |
88 if latest.Value != "" { | 88 if latest.Value != "" { |
89 if err := json.Unmarshal([]byte(latest.Value), &pairs); err != n
il { | 89 if err := json.Unmarshal([]byte(latest.Value), &pairs); err != n
il { |
90 return nil, err | 90 return nil, err |
91 } | 91 } |
92 } | 92 } |
93 return &settings.Bundle{ | 93 return &settings.Bundle{ |
94 Values: pairs, | 94 Values: pairs, |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
144 // Don't store copy of "no settings at all", it's useless. | 144 // Don't store copy of "no settings at all", it's useless. |
145 if latest.Version == 1 { | 145 if latest.Version == 1 { |
146 return ds.Put(c, &latest) | 146 return ds.Put(c, &latest) |
147 } | 147 } |
148 return ds.Put(c, &latest, &auditCopy) | 148 return ds.Put(c, &latest, &auditCopy) |
149 }, nil) | 149 }, nil) |
150 | 150 |
151 if fatalFail != nil { | 151 if fatalFail != nil { |
152 return fatalFail | 152 return fatalFail |
153 } | 153 } |
154 » return errors.WrapTransient(err) | 154 » return retry.Tag.Apply(err) |
155 } | 155 } |
156 | 156 |
157 // GetConsistencyTime returns "last modification time" + "expiration period". | 157 // GetConsistencyTime returns "last modification time" + "expiration period". |
158 // | 158 // |
159 // It indicates moment in time when last setting change is fully propagated to | 159 // It indicates moment in time when last setting change is fully propagated to |
160 // all instances. | 160 // all instances. |
161 // | 161 // |
162 // Returns zero time if there are no settings stored. | 162 // Returns zero time if there are no settings stored. |
163 func (s Storage) GetConsistencyTime(c context.Context) (time.Time, error) { | 163 func (s Storage) GetConsistencyTime(c context.Context) (time.Time, error) { |
164 c = defaultContext(c) | 164 c = defaultContext(c) |
165 latest := latestSettings() | 165 latest := latestSettings() |
166 switch err := ds.Get(c, &latest); err { | 166 switch err := ds.Get(c, &latest); err { |
167 case nil: | 167 case nil: |
168 return latest.When.Add(s.expirationDuration(c)), nil | 168 return latest.When.Add(s.expirationDuration(c)), nil |
169 case ds.ErrNoSuchEntity: | 169 case ds.ErrNoSuchEntity: |
170 return time.Time{}, nil | 170 return time.Time{}, nil |
171 default: | 171 default: |
172 » » return time.Time{}, errors.WrapTransient(err) | 172 » » return time.Time{}, retry.Tag.Apply(err) |
173 } | 173 } |
174 } | 174 } |
OLD | NEW |