Files
golib/atomic/map_test.go
T
Nicolas JUHEL f3b0c6991b Package atomic:
- IMPROVE allocations
- IMPROVE cast process
- ADD test, bench and godoc documentation

Package Duration
- ADD function to format as uint32
- OPTIMIZE parsing to zero allocation process

Package Duration/Big
- ADD function to format as uint32
- OPTIMIZE parsing to zero allocation process

Package Errors:
- IMPROVE allocations
- IMPROVE process contentions
- ADD bench and godoc documentation
- UPDATE test

Package Errors/Pool:
- IMPROVE allocations
- IMPROVE process contentions
- OPTIMIZE package to prevent latency when parsing all map
- OPTIMIZE package to use zero allocation or near
- OPTIMIZE package to avoid many of slice
- UPDATE tests
- ADD bench and godoc documentation

Package Runner:
- UPDATE documentation
- UPDATE ticker function with new interface to only allow Reset function to update time ticker

Package Runner/StartStop:
- IMPROVE allocations
- IMPROVE state, start, stop, context process
- ADD bench and godoc documentation
- UPDATE test

Package Runner/Ticker:
- IMPROVE allocations
- IMPROVE state, start, stop, context process
- ADD bench and godoc documentation
- UPDATE test

Package IOUtils/Aggregator:
- IMPROVE allocations
- IMPROVE runner, context process
- UPDATE bench(from gmeasur to go bench), test and godoc documentation

Package Monitor:
- UPDATE runner/ticker function to apply change following runner type change

Package Logger/HookFile:
- IMPROVE statement fire to use pre-allocated formatting function
- UPDATE aggregator initialising to wait instance is started
- UPDATE test, bench

Package Logger/HookSyslog:
- IMPROVE statement fire to use pre-allocated formatting function
- UPDATE aggregator initialising to wait instance is started
- ADD bench

Package Size
- OPTIMIZE package to zero allocation (except stringer & parsing)
- OPTIMIZE CPU flow
- FIX bug in arithmetic & stringer function
- UPDATE test

Package Socket/server
- OPTIMIZE all socket server to reduce allocation or use pre-allocated resources
- OPTIMIZE all socker server to reduce CPU statment
- OPTIMIZE all socket server to prevent un-omnipotent process
- UPDATE documentation & test

Package Socket/Idle Manager
- ADD new package to centralize all timer/ticker in only one
- OPTIMIZE cpu statment by using pre-allocation & sharding
- OPTIMIZE allocation with sync pool and pre-allocation of shard
- ADD test
2026-04-15 08:09:12 +02:00

182 lines
4.8 KiB
Go

/*
* MIT License
*
* Copyright (c) 2024 Nicolas JUHEL
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*
*/
package atomic_test
import (
"sync"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
libatm "github.com/nabbar/golib/atomic"
)
var _ = Describe("Map implementations", func() {
Context("MapAny[K]", func() {
It("supports Store/Load/Delete/LoadAndDelete/LoadOrStore/Swap/CompareAndSwap/CompareAndDelete/Range", func() {
m := libatm.NewMapAny[string]()
// Store & Load
m.Store("a", 1)
v, ok := m.Load("a")
Expect(ok).To(BeTrue())
Expect(v).To(Equal(1))
// LoadOrStore existing
act, loaded := m.LoadOrStore("a", 2)
Expect(loaded).To(BeTrue())
Expect(act).To(Equal(1))
// LoadOrStore new
act, loaded = m.LoadOrStore("b", 3)
Expect(loaded).To(BeFalse())
Expect(act).To(Equal(3))
// CompareAndSwap
Expect(m.CompareAndSwap("a", 1, 10)).To(BeTrue())
v, _ = m.Load("a")
Expect(v).To(Equal(10))
// Swap
prev, loaded := m.Swap("b", 30)
Expect(loaded).To(BeTrue())
Expect(prev).To(Equal(3))
v, _ = m.Load("b")
Expect(v).To(Equal(30))
// CompareAndDelete
Expect(m.CompareAndDelete("b", 30)).To(BeTrue())
_, ok = m.Load("b")
Expect(ok).To(BeFalse())
// LoadAndDelete
vv, loaded := m.LoadAndDelete("a")
Expect(loaded).To(BeTrue())
Expect(vv).To(Equal(10))
_, ok = m.Load("a")
Expect(ok).To(BeFalse())
// Range with bad key type should auto-delete
m.Store("x", 99)
// Inject bad key type using export_test functionality
if mi, ok := m.(interface{ GetUnderlyingMap() *sync.Map }); ok {
mi.GetUnderlyingMap().Store(123, "bad key type")
}
var seenKeys []string
m.Range(func(k string, val any) bool {
seenKeys = append(seenKeys, k)
return true
})
Expect(seenKeys).To(ContainElement("x"))
Expect(seenKeys).ToNot(ContainElement(123))
// Verify bad key was deleted
if mi, ok := m.(interface{ GetUnderlyingMap() *sync.Map }); ok {
_, ok = mi.GetUnderlyingMap().Load(123)
Expect(ok).To(BeFalse())
}
// Delete
m.Delete("x")
_, ok = m.Load("x")
Expect(ok).To(BeFalse())
})
It("is safe under concurrency for basic operations", func() {
m := libatm.NewMapAny[int]()
var wg sync.WaitGroup
for i := 0; i < 50; i++ {
wg.Add(1)
go func(i int) {
defer wg.Done()
m.Store(i, i)
_, _ = m.Load(i)
m.CompareAndSwap(i, i, i+1)
m.Delete(i + 1)
}(i)
}
wg.Wait()
})
})
Context("MapTyped[K,V]", func() {
It("wraps MapAny with typed API and Range casting", func() {
m := libatm.NewMapTyped[string, int]()
// Store & Load
m.Store("a", 1)
v, ok := m.Load("a")
Expect(ok).To(BeTrue())
Expect(v).To(Equal(1))
// LoadOrStore
act, loaded := m.LoadOrStore("a", 2)
Expect(loaded).To(BeTrue())
Expect(act).To(Equal(1))
act, loaded = m.LoadOrStore("b", 3)
Expect(loaded).To(BeFalse())
Expect(act).To(Equal(3))
// Swap
prev, loaded := m.Swap("b", 30)
Expect(loaded).To(BeTrue())
Expect(prev).To(Equal(3))
// CompareAndSwap / CompareAndDelete
Expect(m.CompareAndSwap("a", 1, 10)).To(BeTrue())
Expect(m.CompareAndDelete("a", 10)).To(BeTrue())
_, ok = m.Load("a")
Expect(ok).To(BeFalse())
// LoadAndDelete
val, ok := m.LoadAndDelete("b")
Expect(ok).To(BeTrue())
Expect(val).To(Equal(30))
// Range
m.Store("x", 5)
// Inject bad value type using export_test functionality
if mi, ok := m.(interface{ GetUnderlyingMap() libatm.Map[string] }); ok {
mi.GetUnderlyingMap().Store("bad", "not an int")
}
var seen []string
m.Range(func(k string, v int) bool {
seen = append(seen, k)
return true
})
Expect(seen).To(ContainElement("x"))
Expect(seen).ToNot(ContainElement("bad"))
// Verify bad value was deleted
_, ok = m.Load("bad")
Expect(ok).To(BeFalse())
})
})
})