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  }