this repo has no description
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

mst: optimize deserializeNodeData allocs, isValidMstKey CPU

isValidMstKey used regexp, which isn't super fast in Go. Write it out
by hand instead, making it much faster:

│ before │ after │
│ sec/op │ sec/op vs base │
IsValidMstKey-8 276.15n ± 1% 27.49n ± 4% -90.05% (p=0.000 n=10)

Also, allocate less in deserializeNodeData, reusing a scratch buffer
between entries and only doing the []byte to string conversion once.

authored by

Brad Fitzpatrick and committed by
bnewbold
0036e0e8 0447a5d2

+37 -13
+37 -13
mst/mst_util.go
··· 6 6 "context" 7 7 "crypto/sha256" 8 8 "fmt" 9 - "regexp" 10 9 "strings" 11 10 "unsafe" 12 11 ··· 78 77 } 79 78 80 79 var lastKey string 80 + var keyb []byte // re-used between entries 81 81 for _, e := range nd.Entries { 82 - key := make([]byte, int(e.PrefixLen)+len(e.KeySuffix)) 83 - copy(key, lastKey[:e.PrefixLen]) 84 - copy(key[e.PrefixLen:], e.KeySuffix) 82 + if keyb == nil { 83 + keyb = make([]byte, 0, int(e.PrefixLen)+len(e.KeySuffix)) 84 + } 85 + keyb = append(keyb[:0], lastKey[:e.PrefixLen]...) 86 + keyb = append(keyb, e.KeySuffix...) 85 87 86 - err := ensureValidMstKey(string(key)) 88 + keyStr := string(keyb) 89 + err := ensureValidMstKey(keyStr) 87 90 if err != nil { 88 91 return nil, err 89 92 } 90 93 91 94 entries = append(entries, nodeEntry{ 92 95 Kind: entryLeaf, 93 - Key: string(key), 96 + Key: keyStr, 94 97 Val: e.Val, 95 98 }) 96 99 ··· 98 101 entries = append(entries, nodeEntry{ 99 102 Kind: entryTree, 100 103 Tree: createMST(cst, *e.Tree, nil, layer-1), 101 - Key: string(key), 104 + Key: keyStr, 102 105 }) 103 106 } 104 - lastKey = string(key) 107 + lastKey = keyStr 105 108 } 106 109 107 110 return entries, nil ··· 200 203 return cst.Put(ctx, nd) 201 204 } 202 205 203 - var reMstKeyChars = regexp.MustCompile("^[a-zA-Z0-9_:.-]+$") 206 + // keyHasAllValidChars reports whether s matches 207 + // the regexp /^[a-zA-Z0-9_:.-]+$/ without using regexp, 208 + // which is slower. 209 + func keyHasAllValidChars(s string) bool { 210 + if len(s) == 0 { 211 + return false 212 + } 213 + for i := 0; i < len(s); i++ { 214 + b := s[i] 215 + if 'a' <= b && b <= 'z' || 216 + 'A' <= b && b <= 'Z' || 217 + '0' <= b && b <= '9' { 218 + continue 219 + } 220 + switch b { 221 + case '_', ':', '.', '-': 222 + continue 223 + default: 224 + return false 225 + } 226 + } 227 + return true 228 + } 204 229 205 230 // Typescript: isValidMstKey(str) 206 231 func isValidMstKey(s string) bool { ··· 208 233 return false 209 234 } 210 235 a, b, _ := strings.Cut(s, "/") 211 - return len(a) > 0 && 212 - len(b) > 1 && 213 - reMstKeyChars.MatchString(a) && 214 - reMstKeyChars.MatchString(b) 236 + return len(b) > 1 && 237 + keyHasAllValidChars(a) && 238 + keyHasAllValidChars(b) 215 239 } 216 240 217 241 // Typescript: ensureValidMstKey(str)