github.com/bytedance/gopkg@v0.0.0-20240514070511-01b2cbcf35e1/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 // CountPersistentValues counts the length of persisten KV pairs 215 func CountPersistentValues(ctx context.Context) int { 216 if n := getNode(ctx); n == nil { 217 return 0 218 } else { 219 return len(n.persistent) 220 } 221 } 222 223 // CountValues counts the length of transient KV pairs 224 func CountValues(ctx context.Context) int { 225 if n := getNode(ctx); n == nil { 226 return 0 227 } else { 228 return len(n.stale) + len(n.transient) 229 } 230 } 231 232 // WithPersistentValues sets the values into the context by the given keys. 233 // This value will be propagated to the services along the RPC call chain. 234 func WithPersistentValues(ctx context.Context, kvs ...string) context.Context { 235 if len(kvs)%2 != 0 { 236 panic("len(kvs) must be even") 237 } 238 239 kvLen := len(kvs) / 2 240 241 if ctx == nil || len(kvs) == 0 { 242 return ctx 243 } 244 245 var n *node 246 if m := getNode(ctx); m != nil { 247 nn := *m 248 n = &nn 249 n.persistent = make([]kv, len(m.persistent), len(m.persistent)+kvLen) 250 copy(n.persistent, m.persistent) 251 } else { 252 n = &node{ 253 persistent: make([]kv, 0, kvLen), 254 } 255 } 256 257 for i := 0; i < kvLen; i++ { 258 key := getKey(kvs, i) 259 val := getValue(kvs, i) 260 261 if len(key) == 0 || len(val) == 0 { 262 continue 263 } 264 265 if idx, ok := search(n.persistent, key); ok { 266 if n.persistent[idx].val != val { 267 n.persistent[idx].val = val 268 } 269 } else { 270 n.persistent = append(n.persistent, kv{key: key, val: val}) 271 } 272 } 273 274 return withNode(ctx, n) 275 } 276 277 // WithValue sets the values into the context by the given keys. 278 // This value will be propagated to the next service/endpoint through an RPC call. 279 // 280 // Notice that it will not propagate any further beyond the next service/endpoint, 281 // Use WithPersistentValues if you want to pass key/value pairs all the way. 282 func WithValues(ctx context.Context, kvs ...string) context.Context { 283 if len(kvs)%2 != 0 { 284 panic("len(kvs) must be even") 285 } 286 287 kvLen := len(kvs) / 2 288 289 if ctx == nil || len(kvs) == 0 { 290 return ctx 291 } 292 293 var n *node 294 if m := getNode(ctx); m != nil { 295 nn := *m 296 n = &nn 297 n.transient = make([]kv, len(m.transient), len(m.transient)+kvLen) 298 copy(n.transient, m.transient) 299 } else { 300 n = &node{ 301 transient: make([]kv, 0, kvLen), 302 } 303 } 304 305 for i := 0; i < kvLen; i++ { 306 key := getKey(kvs, i) 307 val := getValue(kvs, i) 308 309 if len(key) == 0 || len(val) == 0 { 310 continue 311 } 312 313 if res, ok := remove(n.stale, key); ok { 314 n.stale = res 315 n.transient = append(n.transient, kv{key: key, val: val}) 316 continue 317 } 318 319 if idx, ok := search(n.transient, key); ok { 320 if n.transient[idx].val != val { 321 n.transient[idx].val = val 322 } 323 } else { 324 n.transient = append(n.transient, kv{key: key, val: val}) 325 } 326 } 327 328 return withNode(ctx, n) 329 }