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 dscache | 5 package dscache |
6 | 6 |
7 import ( | 7 import ( |
8 "fmt" | 8 "fmt" |
9 "math/rand" | 9 "math/rand" |
10 "time" | 10 "time" |
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
76 if !key.IsIncomplete() { | 76 if !key.IsIncomplete() { |
77 keySuffix := HashKey(key) | 77 keySuffix := HashKey(key) |
78 for shard := 0; shard < nums[i]; shard++ { | 78 for shard := 0; shard < nums[i]; shard++ { |
79 ret = append(ret, fmt.Sprintf(KeyFormat, shard,
keySuffix)) | 79 ret = append(ret, fmt.Sprintf(KeyFormat, shard,
keySuffix)) |
80 } | 80 } |
81 } | 81 } |
82 } | 82 } |
83 return ret | 83 return ret |
84 } | 84 } |
85 | 85 |
86 // crappyNonce creates a really crappy nonce using math/rand. This is generally | |
87 // unacceptable for cryptographic purposes, but since mathrand is the only | |
88 // mocked randomness source, we use that. | |
89 // | |
90 // The random values here are controlled entriely by the application, will never | |
91 // be shown to, or provided by, the user, so this should be fine. | |
92 // | |
93 // Do not use this function for anything other than mkRandLockItems or your hair | |
94 // will fall out. You've been warned. | |
95 func (s *supportContext) crappyNonce() []byte { | |
96 ret := make([]byte, NonceUint32s*4) | |
97 for w := uint(0); w < NonceUint32s; w++ { | |
98 word := s.mr.Uint32() | |
99 for i := uint(0); i < 4; i++ { | |
100 ret[(w*4)+i] = byte(word >> (8 * i)) | |
101 } | |
102 } | |
103 return ret | |
104 } | |
105 | |
106 func (s *supportContext) mutation(keys []*ds.Key, f func() error) error { | 86 func (s *supportContext) mutation(keys []*ds.Key, f func() error) error { |
107 lockItems, lockKeys := s.mkAllLockItems(keys) | 87 lockItems, lockKeys := s.mkAllLockItems(keys) |
108 if lockItems == nil { | 88 if lockItems == nil { |
109 return f() | 89 return f() |
110 } | 90 } |
111 if err := mc.Set(s.c, lockItems...); err != nil { | 91 if err := mc.Set(s.c, lockItems...); err != nil { |
112 // this is a hard failure. No mutation can occur if we're unable
to set | 92 // this is a hard failure. No mutation can occur if we're unable
to set |
113 // locks out. See "DANGER ZONE" in the docs. | 93 // locks out. See "DANGER ZONE" in the docs. |
114 (log.Fields{log.ErrorKey: err}).Errorf( | 94 (log.Fields{log.ErrorKey: err}).Errorf( |
115 s.c, "dscache: HARD FAILURE: supportContext.mutation():
mc.SetMulti") | 95 s.c, "dscache: HARD FAILURE: supportContext.mutation():
mc.SetMulti") |
116 return err | 96 return err |
117 } | 97 } |
118 err := f() | 98 err := f() |
119 if err == nil { | 99 if err == nil { |
120 if err := errors.Filter(mc.Delete(s.c, lockKeys...), mc.ErrCache
Miss); err != nil { | 100 if err := errors.Filter(mc.Delete(s.c, lockKeys...), mc.ErrCache
Miss); err != nil { |
121 (log.Fields{log.ErrorKey: err}).Debugf( | 101 (log.Fields{log.ErrorKey: err}).Debugf( |
122 s.c, "dscache: mc.Delete") | 102 s.c, "dscache: mc.Delete") |
123 } | 103 } |
124 } | 104 } |
125 return err | 105 return err |
126 } | 106 } |
127 | 107 |
128 func (s *supportContext) mkRandLockItems(keys []*ds.Key, metas ds.MultiMetaGette
r) ([]mc.Item, []byte) { | 108 func (s *supportContext) mkRandLockItems(keys []*ds.Key, metas ds.MultiMetaGette
r) ([]mc.Item, []byte) { |
129 mcKeys := s.mkRandKeys(keys, metas) | 109 mcKeys := s.mkRandKeys(keys, metas) |
130 if len(mcKeys) == 0 { | 110 if len(mcKeys) == 0 { |
131 return nil, nil | 111 return nil, nil |
132 } | 112 } |
133 » nonce := s.crappyNonce() | 113 » nonce := generateNonce() |
134 ret := make([]mc.Item, len(mcKeys)) | 114 ret := make([]mc.Item, len(mcKeys)) |
135 for i, k := range mcKeys { | 115 for i, k := range mcKeys { |
136 if k == "" { | 116 if k == "" { |
137 continue | 117 continue |
138 } | 118 } |
139 ret[i] = (mc.NewItem(s.c, k). | 119 ret[i] = (mc.NewItem(s.c, k). |
140 SetFlags(uint32(ItemHasLock)). | 120 SetFlags(uint32(ItemHasLock)). |
141 SetExpiration(time.Second * time.Duration(LockTimeSecond
s)). | 121 SetExpiration(time.Second * time.Duration(LockTimeSecond
s)). |
142 SetValue(nonce)) | 122 SetValue(nonce)) |
143 } | 123 } |
144 return ret, nonce | 124 return ret, nonce |
145 } | 125 } |
146 | 126 |
147 func (s *supportContext) mkAllLockItems(keys []*ds.Key) ([]mc.Item, []string) { | 127 func (s *supportContext) mkAllLockItems(keys []*ds.Key) ([]mc.Item, []string) { |
148 mcKeys := s.mkAllKeys(keys) | 128 mcKeys := s.mkAllKeys(keys) |
149 if mcKeys == nil { | 129 if mcKeys == nil { |
150 return nil, nil | 130 return nil, nil |
151 } | 131 } |
152 ret := make([]mc.Item, len(mcKeys)) | 132 ret := make([]mc.Item, len(mcKeys)) |
153 for i := range ret { | 133 for i := range ret { |
154 ret[i] = (mc.NewItem(s.c, mcKeys[i]). | 134 ret[i] = (mc.NewItem(s.c, mcKeys[i]). |
155 SetFlags(uint32(ItemHasLock)). | 135 SetFlags(uint32(ItemHasLock)). |
156 SetExpiration(time.Second * time.Duration(LockTimeSecond
s))) | 136 SetExpiration(time.Second * time.Duration(LockTimeSecond
s))) |
157 } | 137 } |
158 return ret, mcKeys | 138 return ret, mcKeys |
159 } | 139 } |
| 140 |
| 141 // generateNonce creates a pseudo-random sequence of bytes for use as a nonce |
| 142 // usingthe non-cryptographic PRNG in "math/rand". |
| 143 // |
| 144 // The random values here are controlled entriely by the application, will never |
| 145 // be shown to, or provided by, the user, so this should be fine. |
| 146 func generateNonce() []byte { |
| 147 nonce := make([]byte, NonceBytes) |
| 148 _, _ = rand.Read(nonce) // This Read will always return len(nonce), nil. |
| 149 return nonce |
| 150 } |
OLD | NEW |