github.com/bytedance/gopkg@v0.0.0-20240514070511-01b2cbcf35e1/cloud/metainfo/utils.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 "strings" 20 ) 21 22 // HasMetaInfo detects whether the given context contains metainfo. 23 func HasMetaInfo(ctx context.Context) bool { 24 return getNode(ctx) != nil 25 } 26 27 // SetMetaInfoFromMap retrieves metainfo key-value pairs from the given map and sets then into the context. 28 // Only those keys with prefixes defined in this module would be used. 29 // If the context has been carrying metanifo pairs, they will be merged as a basis. 30 func SetMetaInfoFromMap(ctx context.Context, m map[string]string) context.Context { 31 if ctx == nil || len(m) == 0 { 32 return ctx 33 } 34 35 nd := getNode(ctx) 36 if nd == nil || nd.size() == 0 { 37 // fast path 38 return newCtxFromMap(ctx, m) 39 } 40 // inherit from node 41 mapSize := len(m) 42 persistent := newKVStore(mapSize) 43 transient := newKVStore(mapSize) 44 stale := newKVStore(mapSize) 45 sliceToMap(nd.persistent, persistent) 46 sliceToMap(nd.transient, transient) 47 sliceToMap(nd.stale, stale) 48 49 // insert new kvs from m to node 50 for k, v := range m { 51 if len(k) == 0 || len(v) == 0 { 52 continue 53 } 54 switch { 55 case strings.HasPrefix(k, PrefixTransientUpstream): 56 if len(k) > lenPTU { // do not move this condition to the case statement to prevent a PTU matches PT 57 stale[k[lenPTU:]] = v 58 } 59 case strings.HasPrefix(k, PrefixTransient): 60 if len(k) > lenPT { 61 transient[k[lenPT:]] = v 62 } 63 case strings.HasPrefix(k, PrefixPersistent): 64 if len(k) > lenPP { 65 persistent[k[lenPP:]] = v 66 } 67 } 68 } 69 70 // return original ctx if no invalid key in map 71 if (persistent.size() + transient.size() + stale.size()) == 0 { 72 return ctx 73 } 74 75 // make new node, and transfer map to list 76 nd = newNodeFromMaps(persistent, transient, stale) 77 persistent.recycle() 78 transient.recycle() 79 stale.recycle() 80 return withNode(ctx, nd) 81 } 82 83 func newCtxFromMap(ctx context.Context, m map[string]string) context.Context { 84 // make new node 85 mapSize := len(m) 86 nd := &node{ 87 persistent: make([]kv, 0, mapSize), 88 transient: make([]kv, 0, mapSize), 89 stale: make([]kv, 0, mapSize), 90 } 91 92 // insert new kvs from m to node 93 for k, v := range m { 94 if len(k) == 0 || len(v) == 0 { 95 continue 96 } 97 switch { 98 case strings.HasPrefix(k, PrefixTransientUpstream): 99 if len(k) > lenPTU { // do not move this condition to the case statement to prevent a PTU matches PT 100 nd.stale = append(nd.stale, kv{key: k[lenPTU:], val: v}) 101 } 102 case strings.HasPrefix(k, PrefixTransient): 103 if len(k) > lenPT { 104 nd.transient = append(nd.transient, kv{key: k[lenPT:], val: v}) 105 } 106 case strings.HasPrefix(k, PrefixPersistent): 107 if len(k) > lenPP { 108 nd.persistent = append(nd.persistent, kv{key: k[lenPP:], val: v}) 109 } 110 } 111 } 112 113 // return original ctx if no invalid key in map 114 if nd.size() == 0 { 115 return ctx 116 } 117 return withNode(ctx, nd) 118 } 119 120 // SaveMetaInfoToMap set key-value pairs from ctx to m while filtering out transient-upstream data. 121 func SaveMetaInfoToMap(ctx context.Context, m map[string]string) { 122 if ctx == nil || m == nil { 123 return 124 } 125 ctx = TransferForward(ctx) 126 if n := getNode(ctx); n != nil { 127 for _, kv := range n.stale { 128 m[PrefixTransient+kv.key] = kv.val 129 } 130 for _, kv := range n.transient { 131 m[PrefixTransient+kv.key] = kv.val 132 } 133 for _, kv := range n.persistent { 134 m[PrefixPersistent+kv.key] = kv.val 135 } 136 } 137 } 138 139 // sliceToMap converts a kv slice to map. 140 func sliceToMap(slice []kv, kvs kvstore) { 141 if len(slice) == 0 { 142 return 143 } 144 for _, kv := range slice { 145 kvs[kv.key] = kv.val 146 } 147 }