Documentation
¶
Index ¶
- func AtomicDo[T any](actor *AtomicActor, owner *T, f func(*T))
- func AtomicDoWithInit[T any](actor *AtomicActor, owner *T, f func(*T), initHook func())
- type AtomicActor
- type AtomicGroup
- type BiIndex
- func (s *BiIndex) Assign(name string) (int, bool)
- func (s *BiIndex) Clear()
- func (s *BiIndex) Clone() *BiIndex
- func (s *BiIndex) DeleteAndShift(id int) (string, map[int]int, bool)
- func (s *BiIndex) DeleteByID(id int) (string, bool)
- func (s *BiIndex) DeleteByName(name string) bool
- func (s *BiIndex) Get(id int) (string, bool)
- func (s *BiIndex) Has(name string) bool
- func (s *BiIndex) IDs() []int
- func (s *BiIndex) Index(name string) (int, bool)
- func (s *BiIndex) Len() int
- func (s *BiIndex) Set(id int, name string) (string, bool)
- type Ring
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func AtomicDo ¶ added in v0.2.14
func AtomicDo[T any](actor *AtomicActor, owner *T, f func(*T))
AtomicDo executes f with actor-style serialisation.
func AtomicDoWithInit ¶ added in v0.2.14
func AtomicDoWithInit[T any](actor *AtomicActor, owner *T, f func(*T), initHook func())
AtomicDoWithInit executes f with actor-style serialisation and runs initHook once on the very first AtomicDo call against this actor.
Re-entry rules:
- If the calling goroutine already holds THIS actor → run inline.
- If the calling goroutine is inside SOME other actor of the same group → run inline (legacy "trust zone" semantics).
- Otherwise → acquire the mutex, mark holder, run f, release.
`initHook` is invoked exactly once across the actor's lifetime, on the first AtomicDo call. It typically registers a finalizer or warms a resource. Kept compatible with the previous API.
Types ¶
type AtomicActor ¶ added in v0.2.14
type AtomicActor struct {
// contains filtered or unexported fields
}
AtomicActor provides actor-style serialised execution for any struct. Use AtomicDo to run a function with serialised access.
Implementation: a sync.Mutex protects the actor; the goroutine that holds the mutex stores its goroutine ID in `holder` so that recursive (same-goroutine) AtomicDo calls run inline without deadlocking. The previous implementation used a goroutine-per-actor + channel-based dispatch + runtime.Stack-based goroutine-ID extraction; benchmarks showed 6.7µs per cold AtomicDo just on the framework overhead. With petermattis/goid (cross-platform, ~5ns goroutine-ID extraction) and a plain mutex, that drops to ~30ns per cold call — a measured 169× reduction on the typical "outer.Mean+Stdev+Len" T-test pattern (15.2µs → 0.09µs per invocation).
API surface is unchanged from the previous channel-actor design so callers in `insyra` and `stats` recompile without source changes.
func NewAtomicActor ¶ added in v0.2.14
func NewAtomicActor(group *AtomicGroup) *AtomicActor
NewAtomicActor creates a new AtomicActor bound to the provided group. If group is nil, DefaultAtomicGroup is used.
func (*AtomicActor) Close ¶ added in v0.2.14
func (a *AtomicActor) Close()
Close marks the actor as closed. Subsequent AtomicDo calls run inline (no locking) so close-during-shutdown paths can't deadlock.
func (*AtomicActor) IsClosed ¶ added in v0.2.14
func (a *AtomicActor) IsClosed() bool
IsClosed reports whether Close was called.
func (*AtomicActor) SetGroupOnce ¶ added in v0.2.14
func (a *AtomicActor) SetGroupOnce(group *AtomicGroup)
SetGroupOnce assigns the re-entrancy group for this actor once.
type AtomicGroup ¶ added in v0.2.14
type AtomicGroup struct {
// contains filtered or unexported fields
}
AtomicGroup defines a re-entrancy scope for AtomicActor.
If a goroutine is already inside SOME actor belonging to the same group, subsequent AtomicDo calls on actors of the same group run inline without re-acquiring a mutex. This preserves the previous channel-actor design's "trust zone" semantics: callers within the zone may co-access multiple actors without nested locking, accepting the same race exposure as before. (The previous implementation also short-circuited cross-actor nested calls; not preserving this would break stats methods that do `dlX.AtomicDo(func() { dlY.AtomicDo(... read x, read y ...) })`.)
func DefaultAtomicGroup ¶ added in v0.2.14
func DefaultAtomicGroup() *AtomicGroup
DefaultAtomicGroup returns the package-wide default group.
func NewAtomicGroup ¶ added in v0.2.14
func NewAtomicGroup() *AtomicGroup
NewAtomicGroup creates a new AtomicGroup.
type BiIndex ¶
type BiIndex struct {
// contains filtered or unexported fields
}
BiIndex maps between integer ids and string names with stable ids. Deleted ids are pushed onto a free list for reuse.
func NewBiIndex ¶
NewBiIndex create a new BiIndex with optional capacity hint.
func (*BiIndex) Assign ¶
Assign assigns a new id for name if it doesn't exist, reusing freed ids if any. Returns (id, true) if newly assigned, or (existingID, false) if name existed.
func (*BiIndex) Clear ¶
func (s *BiIndex) Clear()
Clear removes all mappings and resets free list and counters.
func (*BiIndex) DeleteAndShift ¶
DeleteAndShift deletes the mapping at id and shifts all mappings with ids greater than id down by 1. It returns the deleted name, a mapping of oldID->newID for all shifted ids, and true on success. This operation is O(n) and will change many ids; mapping helps callers update references.
func (*BiIndex) DeleteByID ¶
DeleteByID removes the mapping at id and returns the deleted name. The id is pushed to free list for reuse.
func (*BiIndex) DeleteByName ¶
DeleteByName removes the mapping for name.
type Ring ¶ added in v0.2.14
type Ring[T any] struct { // contains filtered or unexported fields }
Ring is a non-thread-safe circular buffer with dynamic growth. It is suitable for building higher-level queues or error rings.
func (*Ring[T]) Clear ¶ added in v0.2.14
func (r *Ring[T]) Clear()
Clear removes all elements while keeping the capacity.