| 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 |