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 }