1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81
|
// Copyright (c) 2025 Karl Gaissmaier
// SPDX-License-Identifier: MIT
package bart_test
import (
"sync"
"sync/atomic"
"github.com/gaissmai/bart"
)
// ExampleLite_concurrent demonstrates safe concurrent usage of bart.Lite.
//
// This example is intended to be run with the Go race detector enabled
// (use `go test -race -run=ExampleLite_concurrent`)
// to verify that concurrent access is safe and free of data races.
//
// This example demonstrates how multiple goroutines perform lock-free, concurrent reads
// via an atomic pointer, while synchronizing writers with a mutex to ensure exclusive access.
// This concurrency pattern is useful when reads are frequent and writes are rare
// or take a long time in comparison to reads,
// providing high performance for concurrent workloads.
func ExampleLite_concurrent() {
var liteAtomicPtr atomic.Pointer[bart.Lite]
var liteMutex sync.Mutex
baseTbl := new(bart.Lite)
liteAtomicPtr.Store(baseTbl)
wg := sync.WaitGroup{}
wg.Add(1)
go func() {
defer wg.Done()
for range 10_000 {
for _, ip := range exampleIPs {
_ = liteAtomicPtr.Load().Contains(ip)
}
}
}()
wg.Add(1)
go func() {
defer wg.Done()
for range 1000 {
liteMutex.Lock()
cur := liteAtomicPtr.Load()
// batch of inserts
next := cur
for _, pfx := range examplePrefixes {
next = next.InsertPersist(pfx)
}
liteAtomicPtr.Store(next)
liteMutex.Unlock()
}
}()
wg.Add(1)
go func() {
defer wg.Done()
for range 1000 {
liteMutex.Lock()
cur := liteAtomicPtr.Load()
// batch of deletes
next := cur
for _, pfx := range examplePrefixes {
next = next.DeletePersist(pfx)
}
liteAtomicPtr.Store(next)
liteMutex.Unlock()
}
}()
wg.Wait()
// Output:
}
|