github.com/bytedance/gopkg@v0.0.0-20240514070511-01b2cbcf35e1/cloud/metainfo/kv.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  type ctxKeyType struct{}
    22  
    23  var ctxKey ctxKeyType
    24  
    25  type kv struct {
    26  	key string
    27  	val string
    28  }
    29  
    30  func newNodeFromMaps(persistent, transient, stale kvstore) *node {
    31  	ps, ts, sz := persistent.size(), transient.size(), stale.size()
    32  	// make slices together to reduce malloc cost
    33  	kvs := make([]kv, ps+ts+sz)
    34  	nd := new(node)
    35  	nd.persistent = kvs[:ps]
    36  	nd.transient = kvs[ps : ps+ts]
    37  	nd.stale = kvs[ps+ts:]
    38  
    39  	i := 0
    40  	for k, v := range persistent {
    41  		nd.persistent[i].key, nd.persistent[i].val = k, v
    42  		i++
    43  	}
    44  	i = 0
    45  	for k, v := range transient {
    46  		nd.transient[i].key, nd.transient[i].val = k, v
    47  		i++
    48  	}
    49  	i = 0
    50  	for k, v := range stale {
    51  		nd.stale[i].key, nd.stale[i].val = k, v
    52  		i++
    53  	}
    54  	return nd
    55  }
    56  
    57  type node struct {
    58  	persistent []kv
    59  	transient  []kv
    60  	stale      []kv
    61  }
    62  
    63  func (n *node) size() int {
    64  	return len(n.persistent) + len(n.transient) + len(n.stale)
    65  }
    66  
    67  func (n *node) transferForward() (r *node) {
    68  	r = &node{
    69  		persistent: n.persistent,
    70  		stale:      n.transient,
    71  	}
    72  	return
    73  }
    74  
    75  func (n *node) addTransient(k, v string) *node {
    76  	if res, ok := remove(n.stale, k); ok {
    77  		return &node{
    78  			persistent: n.persistent,
    79  			transient: appendEx(n.transient, kv{
    80  				key: k,
    81  				val: v,
    82  			}),
    83  			stale: res,
    84  		}
    85  	}
    86  
    87  	if idx, ok := search(n.transient, k); ok {
    88  		if n.transient[idx].val == v {
    89  			return n
    90  		}
    91  		r := *n
    92  		r.transient = make([]kv, len(n.transient))
    93  		copy(r.transient, n.transient)
    94  		r.transient[idx].val = v
    95  		return &r
    96  	}
    97  
    98  	r := *n
    99  	r.transient = appendEx(r.transient, kv{
   100  		key: k,
   101  		val: v,
   102  	})
   103  	return &r
   104  }
   105  
   106  func (n *node) addPersistent(k, v string) *node {
   107  	if idx, ok := search(n.persistent, k); ok {
   108  		if n.persistent[idx].val == v {
   109  			return n
   110  		}
   111  		r := *n
   112  		r.persistent = make([]kv, len(n.persistent))
   113  		copy(r.persistent, n.persistent)
   114  		r.persistent[idx].val = v
   115  		return &r
   116  	}
   117  	r := *n
   118  	r.persistent = appendEx(r.persistent, kv{
   119  		key: k,
   120  		val: v,
   121  	})
   122  	return &r
   123  }
   124  
   125  func (n *node) delTransient(k string) (r *node) {
   126  	if res, ok := remove(n.stale, k); ok {
   127  		return &node{
   128  			persistent: n.persistent,
   129  			transient:  n.transient,
   130  			stale:      res,
   131  		}
   132  	}
   133  	if res, ok := remove(n.transient, k); ok {
   134  		return &node{
   135  			persistent: n.persistent,
   136  			transient:  res,
   137  			stale:      n.stale,
   138  		}
   139  	}
   140  	return n
   141  }
   142  
   143  func (n *node) delPersistent(k string) (r *node) {
   144  	if res, ok := remove(n.persistent, k); ok {
   145  		return &node{
   146  			persistent: res,
   147  			transient:  n.transient,
   148  			stale:      n.stale,
   149  		}
   150  	}
   151  	return n
   152  }
   153  
   154  func search(kvs []kv, key string) (idx int, ok bool) {
   155  	for i := range kvs {
   156  		if kvs[i].key == key {
   157  			return i, true
   158  		}
   159  	}
   160  	return
   161  }
   162  
   163  func remove(kvs []kv, key string) (res []kv, removed bool) {
   164  	if idx, ok := search(kvs, key); ok {
   165  		if cnt := len(kvs); cnt == 1 {
   166  			removed = true
   167  			return
   168  		}
   169  		res = make([]kv, len(kvs)-1)
   170  		copy(res, kvs[:idx])
   171  		copy(res[idx:], kvs[idx+1:])
   172  		return res, true
   173  	}
   174  	return kvs, false
   175  }
   176  
   177  func getNode(ctx context.Context) *node {
   178  	if ctx != nil {
   179  		if val, ok := ctx.Value(ctxKey).(*node); ok {
   180  			return val
   181  		}
   182  	}
   183  	return nil
   184  }
   185  
   186  func withNode(ctx context.Context, n *node) context.Context {
   187  	if ctx == nil {
   188  		return ctx
   189  	}
   190  	return context.WithValue(ctx, ctxKey, n)
   191  }
   192  
   193  func appendEx(arr []kv, x kv) (res []kv) {
   194  	res = make([]kv, len(arr)+1)
   195  	copy(res, arr)
   196  	res[len(arr)] = x
   197  	return res
   198  }