Source File
tracemap.go
Belonging Package
runtime
// Copyright 2023 The Go Authors. All rights reserved.// Use of this source code is governed by a BSD-style// license that can be found in the LICENSE file.// Simple append-only thread-safe hash map for tracing.// Provides a mapping between variable-length data and a// unique ID. Subsequent puts of the same data will return// the same ID. The zero value is ready to use.//// Uses a region-based allocation scheme internally, and// reset clears the whole map.//// It avoids doing any high-level Go operations so it's safe// to use even in sensitive contexts.package runtimeimport ()type traceMap struct {root atomic.UnsafePointer // *traceMapNode (can't use generics because it's notinheap)_ cpu.CacheLinePadseq atomic.Uint64_ cpu.CacheLinePadmem traceRegionAlloc}// traceMapNode is an implementation of a lock-free append-only hash-trie// (a trie of the hash bits).//// Key features:// - 4-ary trie. Child nodes are indexed by the upper 2 (remaining) bits of the hash.// For example, top level uses bits [63:62], next level uses [61:60] and so on.// - New nodes are placed at the first empty level encountered.// - When the first child is added to a node, the existing value is not moved into a child.// This means that you must check the key at each level, not just at the leaf.// - No deletion or rebalancing.// - Intentionally devolves into a linked list on hash collisions (the hash bits will all// get shifted out during iteration, and new nodes will just be appended to the 0th child).type traceMapNode struct {_ sys.NotInHeapchildren [4]atomic.UnsafePointer // *traceMapNode (can't use generics because it's notinheap)hash uintptrid uint64data []byte}// stealID steals an ID from the table, ensuring that it will not// appear in the table anymore.func ( *traceMap) () uint64 {return .seq.Add(1)}// put inserts the data into the table.//// It's always safe for callers to noescape data because put copies its bytes.//// Returns a unique ID for the data and whether this is the first time// the data has been added to the map.func ( *traceMap) ( unsafe.Pointer, uintptr) (uint64, bool) {if == 0 {return 0, false}:= memhash(, 0, )var *traceMapNode:= &.root:=for {:= (*traceMapNode)(.Load())if == nil {// Try to insert a new map node. We may end up discarding// this node if we fail to insert because it turns out the// value is already in the map.//// The discard will only happen if two threads race on inserting// the same value. Both might create nodes, but only one will// succeed on insertion. If two threads race to insert two// different values, then both nodes will *always* get inserted,// because the equality checking below will always fail.//// Performance note: contention on insertion is likely to be// higher for small maps, but since this data structure is// append-only, either the map stays small because there isn't// much activity, or the map gets big and races to insert on// the same node are much less likely.if == nil {= .newTraceMapNode(, , , .seq.Add(1))}if .CompareAndSwapNoWB(nil, unsafe.Pointer()) {return .id, true}// Reload n. Because pointers are only stored once,// we must have lost the race, and therefore n is not nil// anymore.= (*traceMapNode)(.Load())}if .hash == && uintptr(len(.data)) == {if memequal(unsafe.Pointer(&.data[0]), , ) {return .id, false}}= &.children[>>(8*goarch.PtrSize-2)]<<= 2}}func ( *traceMap) ( unsafe.Pointer, , uintptr, uint64) *traceMapNode {// Create data array.:= notInHeapSlice{array: .mem.alloc(),len: int(),cap: int(),}memmove(unsafe.Pointer(.array), , )// Create metadata structure.:= (*traceMapNode)(unsafe.Pointer(.mem.alloc(unsafe.Sizeof(traceMapNode{}))))*(*notInHeapSlice)(unsafe.Pointer(&.data)) =.id =.hash =return}// reset drops all allocated memory from the table and resets it.//// The caller must ensure that there are no put operations executing concurrently// with this function.func ( *traceMap) () {.root.Store(nil).seq.Store(0).mem.drop()}
![]() |
The pages are generated with Golds v0.7.9-preview. (GOOS=linux GOARCH=amd64) Golds is a Go 101 project developed by Tapir Liu. PR and bug reports are welcome and can be submitted to the issue list. Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds. |