github.com/aaabigfish/gopkg@v1.1.0/cloud/metainfo/info.go (about) 1 // Copyright 2021 ByteDance Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package metainfo 16 17 import ( 18 "context" 19 ) 20 21 // The prefix listed below may be used to tag the types of values when there is no context to carry them. 22 const ( 23 PrefixPersistent = "RPC_PERSIST_" 24 PrefixTransient = "RPC_TRANSIT_" 25 PrefixTransientUpstream = "RPC_TRANSIT_UPSTREAM_" 26 PrefixBackward = "RPC_BACKWARD_" 27 PrefixBackwardDownstream = "RPC_BACKWARD_DOWNSTREAM_" 28 29 lenPTU = len(PrefixTransientUpstream) 30 lenPT = len(PrefixTransient) 31 lenPP = len(PrefixPersistent) 32 lenB = len(PrefixBackward) 33 lenBD = len(PrefixBackwardDownstream) 34 ) 35 36 // **Using empty string as key or value is not support.** 37 38 // TransferForward converts transient values to transient-upstream values and filters out original transient-upstream values. 39 // It should be used before the context is passing from server to client. 40 func TransferForward(ctx context.Context) context.Context { 41 if n := getNode(ctx); n != nil { 42 return withNode(ctx, n.transferForward()) 43 } 44 return ctx 45 } 46 47 // GetValue retrieves the value set into the context by the given key. 48 func GetValue(ctx context.Context, k string) (v string, ok bool) { 49 if n := getNode(ctx); n != nil { 50 if idx, ok := search(n.transient, k); ok { 51 return n.transient[idx].val, true 52 } 53 if idx, ok := search(n.stale, k); ok { 54 return n.stale[idx].val, true 55 } 56 } 57 return 58 } 59 60 // GetAllValues retrieves all transient values 61 func GetAllValues(ctx context.Context) (m map[string]string) { 62 if n := getNode(ctx); n != nil { 63 if cnt := len(n.stale) + len(n.transient); cnt > 0 { 64 m = make(map[string]string, cnt) 65 for _, kv := range n.stale { 66 m[kv.key] = kv.val 67 } 68 for _, kv := range n.transient { 69 m[kv.key] = kv.val 70 } 71 } 72 } 73 return 74 } 75 76 // RangeValues calls f sequentially for each transient kv. 77 // If f returns false, range stops the iteration. 78 func RangeValues(ctx context.Context, f func(k, v string) bool) { 79 n := getNode(ctx) 80 if n == nil { 81 return 82 } 83 84 if cnt := len(n.stale) + len(n.transient); cnt == 0 { 85 return 86 } 87 88 for _, kv := range n.stale { 89 if !f(kv.key, kv.val) { 90 return 91 } 92 } 93 94 for _, kv := range n.transient { 95 if !f(kv.key, kv.val) { 96 return 97 } 98 } 99 } 100 101 // WithValue sets the value into the context by the given key. 102 // This value will be propagated to the next service/endpoint through an RPC call. 103 // 104 // Notice that it will not propagate any further beyond the next service/endpoint, 105 // Use WithPersistentValue if you want to pass a key/value pair all the way. 106 func WithValue(ctx context.Context, k, v string) context.Context { 107 if len(k) == 0 || len(v) == 0 { 108 return ctx 109 } 110 if n := getNode(ctx); n != nil { 111 if m := n.addTransient(k, v); m != n { 112 return withNode(ctx, m) 113 } 114 } else { 115 return withNode(ctx, &node{ 116 transient: []kv{{key: k, val: v}}, 117 }) 118 } 119 return ctx 120 } 121 122 // DelValue deletes a key/value from the current context. 123 // Since empty string value is not valid, we could just set the value to be empty. 124 func DelValue(ctx context.Context, k string) context.Context { 125 if len(k) == 0 { 126 return ctx 127 } 128 if n := getNode(ctx); n != nil { 129 if m := n.delTransient(k); m != n { 130 return withNode(ctx, m) 131 } 132 } 133 return ctx 134 } 135 136 // GetPersistentValue retrieves the persistent value set into the context by the given key. 137 func GetPersistentValue(ctx context.Context, k string) (v string, ok bool) { 138 if n := getNode(ctx); n != nil { 139 if idx, ok := search(n.persistent, k); ok { 140 return n.persistent[idx].val, true 141 } 142 } 143 return 144 } 145 146 // GetAllPersistentValues retrieves all persistent values. 147 func GetAllPersistentValues(ctx context.Context) (m map[string]string) { 148 if n := getNode(ctx); n != nil { 149 if cnt := len(n.persistent); cnt > 0 { 150 m = make(map[string]string, cnt) 151 for _, kv := range n.persistent { 152 m[kv.key] = kv.val 153 } 154 } 155 } 156 return 157 } 158 159 // RangePersistentValues calls f sequentially for each persistent kv. 160 // If f returns false, range stops the iteration. 161 func RangePersistentValues(ctx context.Context, f func(k, v string) bool) { 162 n := getNode(ctx) 163 if n == nil { 164 return 165 } 166 167 for _, kv := range n.persistent { 168 if !f(kv.key, kv.val) { 169 break 170 } 171 } 172 } 173 174 // WithPersistentValue sets the value into the context by the given key. 175 // This value will be propagated to the services along the RPC call chain. 176 func WithPersistentValue(ctx context.Context, k, v string) context.Context { 177 if len(k) == 0 || len(v) == 0 { 178 return ctx 179 } 180 if n := getNode(ctx); n != nil { 181 if m := n.addPersistent(k, v); m != n { 182 return withNode(ctx, m) 183 } 184 } else { 185 return withNode(ctx, &node{ 186 persistent: []kv{{key: k, val: v}}, 187 }) 188 } 189 return ctx 190 } 191 192 // DelPersistentValue deletes a persistent key/value from the current context. 193 // Since empty string value is not valid, we could just set the value to be empty. 194 func DelPersistentValue(ctx context.Context, k string) context.Context { 195 if len(k) == 0 { 196 return ctx 197 } 198 if n := getNode(ctx); n != nil { 199 if m := n.delPersistent(k); m != n { 200 return withNode(ctx, m) 201 } 202 } 203 return ctx 204 } 205 206 func getKey(kvs []string, i int) string { 207 return kvs[i*2] 208 } 209 210 func getValue(kvs []string, i int) string { 211 return kvs[i*2+1] 212 } 213 214 // WithPersistentValues sets the values into the context by the given keys. 215 // This value will be propagated to the services along the RPC call chain. 216 func WithPersistentValues(ctx context.Context, kvs ...string) context.Context { 217 if len(kvs)%2 != 0 { 218 panic("len(kvs) must be even") 219 } 220 221 kvLen := len(kvs) / 2 222 223 if ctx == nil || len(kvs) == 0 { 224 return ctx 225 } 226 227 var n *node 228 if m := getNode(ctx); m != nil { 229 nn := *m 230 n = &nn 231 n.persistent = make([]kv, 0, len(m.persistent)+kvLen) 232 copy(n.persistent, m.persistent) 233 } else { 234 n = &node{ 235 persistent: make([]kv, 0, kvLen), 236 } 237 } 238 239 for i := 0; i < kvLen; i++ { 240 key := getKey(kvs, i) 241 val := getValue(kvs, i) 242 243 if len(key) == 0 || len(val) == 0 { 244 continue 245 } 246 247 if idx, ok := search(n.persistent, key); ok { 248 if n.persistent[idx].val != val { 249 n.persistent[idx].val = val 250 } 251 } else { 252 n.persistent = append(n.persistent, kv{key: key, val: val}) 253 } 254 } 255 256 return withNode(ctx, n) 257 } 258 259 // WithValue sets the values into the context by the given keys. 260 // This value will be propagated to the next service/endpoint through an RPC call. 261 // 262 // Notice that it will not propagate any further beyond the next service/endpoint, 263 // Use WithPersistentValues if you want to pass key/value pairs all the way. 264 func WithValues(ctx context.Context, kvs ...string) context.Context { 265 if len(kvs)%2 != 0 { 266 panic("len(kvs) must be even") 267 } 268 269 kvLen := len(kvs) / 2 270 271 if ctx == nil || len(kvs) == 0 { 272 return ctx 273 } 274 275 var n *node 276 if m := getNode(ctx); m != nil { 277 nn := *m 278 n = &nn 279 n.transient = make([]kv, 0, len(m.transient)+kvLen) 280 copy(n.transient, m.transient) 281 } else { 282 n = &node{ 283 transient: make([]kv, 0, kvLen), 284 } 285 } 286 287 for i := 0; i < kvLen; i++ { 288 key := getKey(kvs, i) 289 val := getValue(kvs, i) 290 291 if len(key) == 0 || len(val) == 0 { 292 continue 293 } 294 295 if res, ok := remove(n.stale, key); ok { 296 n.stale = res 297 n.transient = append(n.transient, kv{key: key, val: val}) 298 continue 299 } 300 301 if idx, ok := search(n.transient, key); ok { 302 if n.transient[idx].val != val { 303 n.transient[idx].val = val 304 } 305 } else { 306 n.transient = append(n.transient, kv{key: key, val: val}) 307 } 308 } 309 310 return withNode(ctx, n) 311 }