2025-06-20 22:04:34 +02:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"sync"
|
|
|
|
"sync/atomic"
|
|
|
|
)
|
|
|
|
|
|
|
|
type RateLimiter struct {
|
|
|
|
sync.Map
|
2025-06-20 22:44:16 +02:00
|
|
|
total atomic.Uint32
|
2025-06-20 22:04:34 +02:00
|
|
|
}
|
|
|
|
|
2025-06-20 22:44:16 +02:00
|
|
|
const MinusOne uint32 = ^uint32(0)
|
|
|
|
|
2025-06-20 22:04:34 +02:00
|
|
|
func NewRateLimiter() *RateLimiter {
|
|
|
|
return &RateLimiter{}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (rl *RateLimiter) Get(key string) *atomic.Uint32 {
|
|
|
|
val, ok := rl.Map.Load(key)
|
|
|
|
if ok {
|
|
|
|
return val.(*atomic.Uint32)
|
|
|
|
}
|
|
|
|
|
|
|
|
actual, _ := rl.Map.LoadOrStore(key, &atomic.Uint32{})
|
|
|
|
|
|
|
|
return actual.(*atomic.Uint32)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (rl *RateLimiter) Inc(key string) (uint32, func(), func()) {
|
2025-06-20 22:44:16 +02:00
|
|
|
if rl.total.Add(1) > MaxGlobalParallel {
|
|
|
|
rl.total.Add(MinusOne)
|
|
|
|
|
|
|
|
return 0, nil, nil
|
|
|
|
}
|
|
|
|
|
2025-06-20 22:04:34 +02:00
|
|
|
val := rl.Get(key)
|
|
|
|
new := val.Add(1)
|
|
|
|
|
|
|
|
var done uint32
|
|
|
|
|
|
|
|
pass := func() {
|
|
|
|
atomic.CompareAndSwapUint32(&done, 0, 1)
|
|
|
|
}
|
|
|
|
|
|
|
|
fail := func() {
|
|
|
|
if !atomic.CompareAndSwapUint32(&done, 0, 1) {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2025-06-20 22:44:16 +02:00
|
|
|
rl.total.Add(MinusOne)
|
|
|
|
val.Add(MinusOne)
|
2025-06-20 22:04:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return new, pass, fail
|
|
|
|
}
|
|
|
|
|
|
|
|
func (rl *RateLimiter) Dec(key string) uint32 {
|
2025-06-20 22:44:16 +02:00
|
|
|
rl.total.Add(MinusOne)
|
|
|
|
|
2025-06-20 22:04:34 +02:00
|
|
|
val := rl.Get(key)
|
|
|
|
|
2025-06-20 22:44:16 +02:00
|
|
|
return val.Add(MinusOne)
|
2025-06-20 22:04:34 +02:00
|
|
|
}
|