mirror of
https://github.com/nabbar/golib.git
synced 2026-04-22 23:17:12 +08:00
f3b0c6991b
- 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
182 lines
4.8 KiB
Go
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())
|
|
})
|
|
})
|
|
})
|