Files
wehub-resource-sync a06f331eb8
CI / benchmark (push) Has been skipped
install-script / posix-syntax (push) Successful in 6m1s
CI / build-onnx (push) Failing after 6m43s
init-smoke / dry-run (push) Failing after 15m57s
security / govulncheck (push) Has been cancelled
security / trivy-fs (push) Has been cancelled
CI / test (1.26, ubuntu-latest) (push) Has been cancelled
Scorecard supply-chain security / Scorecard analysis (push) Has been cancelled
CI / test (1.26, macos-latest) (push) Has been cancelled
CI / build-windows (push) Has been cancelled
CI / lint (push) Has been cancelled
install-script / powershell-syntax (push) Has been cancelled
install-script / install (macos-14) (push) Has been cancelled
install-script / install (ubuntu-latest) (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:33:42 +08:00

84 lines
2.3 KiB
Go

// Package intern provides a process-wide string interning table.
//
// The knowledge graph stores a node's ID once on the node, but also
// once on every edge endpoint that references it, and a file path once
// per node defined in that file. Under a multi-repo warmup those
// references are minted as fresh `repoPrefix + "/" + id` concatenations
// — a heap profile attributed ~425 MB of resident memory to that
// concatenation alone. Interning collapses every duplicate of a string
// to a single shared backing array.
//
// The table is process-global and never shrinks: an interned string
// lives until process exit even if every repo referencing it is later
// evicted. This is a deliberate trade — node IDs and file paths are
// low-cardinality and heavily duplicated, so the bounded table costs
// far less than the duplication it removes.
package intern
import "sync"
// shardCount fans interning lookups across independent locks so the
// parallel warmup workers (one goroutine per repo) do not serialise on
// a single mutex. 64 keeps per-shard maps small without waste.
const shardCount = 64
type shard struct {
mu sync.RWMutex
m map[string]string
}
var shards [shardCount]*shard
func init() {
for i := range shards {
shards[i] = &shard{m: make(map[string]string)}
}
}
// shardFor picks a shard by FNV-1a hash of s — inlined rather than
// using hash/fnv to avoid a hash-object allocation on every call.
func shardFor(s string) *shard {
var h uint32 = 2166136261
for i := 0; i < len(s); i++ {
h ^= uint32(s[i])
h *= 16777619
}
return shards[h%shardCount]
}
// String returns the canonical instance of s. Every call with an equal
// string returns the same backing array, so the caller may drop its
// own copy. The empty string is returned as-is without touching the
// table. Safe for concurrent use.
func String(s string) string {
if s == "" {
return ""
}
sh := shardFor(s)
sh.mu.RLock()
c, ok := sh.m[s]
sh.mu.RUnlock()
if ok {
return c
}
sh.mu.Lock()
if c, ok = sh.m[s]; !ok {
sh.m[s] = s
c = s
}
sh.mu.Unlock()
return c
}
// Len reports the number of distinct strings currently interned.
// Intended for diagnostics and tests.
func Len() int {
n := 0
for _, sh := range shards {
sh.mu.RLock()
n += len(sh.m)
sh.mu.RUnlock()
}
return n
}