mirror of
https://github.com/hanzokv/go.git
synced 2026-09-24 00:31:51 +00:00
We do not use Redis. The client was a go-redis fork and still said so
everywhere: `package redis`, `redis.NewClient`, `redis://`, `extra/redisotel`.
Consumers wrote `redis.Client` against a Valkey-backed store called KV.
package redis -> package kv (93 decls)
redis.X -> kv.X (2,794 call sites)
"redis: …" errors -> "kv: …" (206)
extra/redis{otel,cmd,prometheus,census} -> extra/kv{otel,cmd,prometheus,census}
redis:// , rediss:// -> kv:// , kvs:// (ParseURL)
Redis*/*Redis* idents -> KV*/*KV*
REDIS_VERSION, REDIS_ENDPOINTS_CONFIG_PATH -> KV_*
I previously argued this rename was unsafe because much of it was "wire
contract". That was wrong, and the categorisation shows why: RESP command names
are GET/SET/HSET — they never contain the word. Of 5,771 occurrences only two
kinds were server-visible at all: the ParseURL scheme (we choose what we pass;
our configs already use kv://) and the CLIENT SETINFO lib-name label, which the
server merely records. Nothing here changes a byte of protocol.
Two things deliberately keep the old spelling:
RediSearch — names a specific external module the FT.* commands map to.
StoreDist — contains the letters by accident (sto-reDis-t), not the word.
Breaking for consumers by design: every import site must move redis.X -> kv.X.
Minor bump, never a major — this module stays v9 forever.
97 lines
2.7 KiB
Go
97 lines
2.7 KiB
Go
package util
|
||
|
||
/*
|
||
© 2023–present Harald Rudell <[email protected]> (https://haraldrudell.github.io/haraldrudell/)
|
||
ISC License
|
||
|
||
Modified by htemelski-kv
|
||
Adapted from the modified atomic_max, but with inverted logic
|
||
*/
|
||
|
||
import (
|
||
"math"
|
||
|
||
"go.uber.org/atomic"
|
||
)
|
||
|
||
// AtomicMin is a thread-safe Min container
|
||
// - hasValue indicator true if a value was equal to or greater than threshold
|
||
// - optional threshold for minimum accepted Min value
|
||
// - —
|
||
// - wait-free CompareAndSwap mechanic
|
||
type AtomicMin struct {
|
||
|
||
// value is current Min
|
||
value atomic.Float64
|
||
// whether [AtomicMin.Value] has been invoked
|
||
// with value equal or greater to threshold
|
||
hasValue atomic.Bool
|
||
}
|
||
|
||
// NewAtomicMin returns a thread-safe Min container
|
||
// - if threshold is not used, AtomicMin is initialization-free
|
||
func NewAtomicMin() (atomicMin *AtomicMin) {
|
||
m := AtomicMin{}
|
||
m.value.Store(math.MaxFloat64)
|
||
return &m
|
||
}
|
||
|
||
// Value updates the container with a possible Min value
|
||
// - isNewMin is true if:
|
||
// - — value is equal to or greater than any threshold and
|
||
// - — invocation recorded the first 0 or
|
||
// - — a new Min
|
||
// - upon return, Min and Min1 are guaranteed to reflect the invocation
|
||
// - the return order of concurrent Value invocations is not guaranteed
|
||
// - Thread-safe
|
||
func (m *AtomicMin) Value(value float64) (isNewMin bool) {
|
||
// math.MaxFloat64 as Min case
|
||
var hasValue0 = m.hasValue.Load()
|
||
if value == math.MaxFloat64 {
|
||
if !hasValue0 {
|
||
isNewMin = m.hasValue.CompareAndSwap(false, true)
|
||
}
|
||
return // math.MaxFloat64 as Min: isNewMin true for first 0 writer
|
||
}
|
||
|
||
// check against present value
|
||
var current = m.value.Load()
|
||
if isNewMin = value < current; !isNewMin {
|
||
return // not a new Min return: isNewMin false
|
||
}
|
||
|
||
// store the new Min
|
||
for {
|
||
|
||
// try to write value to *Min
|
||
if isNewMin = m.value.CompareAndSwap(current, value); isNewMin {
|
||
if !hasValue0 {
|
||
// may be rarely written multiple times
|
||
// still faster than CompareAndSwap
|
||
m.hasValue.Store(true)
|
||
}
|
||
return // new Min written return: isNewMin true
|
||
}
|
||
if current = m.value.Load(); current <= value {
|
||
return // no longer a need to write return: isNewMin false
|
||
}
|
||
}
|
||
}
|
||
|
||
// Min returns current min and value-present flag
|
||
// - hasValue true indicates that value reflects a Value invocation
|
||
// - hasValue false: value is zero-value
|
||
// - Thread-safe
|
||
func (m *AtomicMin) Min() (value float64, hasValue bool) {
|
||
if hasValue = m.hasValue.Load(); !hasValue {
|
||
return
|
||
}
|
||
value = m.value.Load()
|
||
return
|
||
}
|
||
|
||
// Min1 returns current Minimum whether zero-value or set by Value
|
||
// - threshold is ignored
|
||
// - Thread-safe
|
||
func (m *AtomicMin) Min1() (value float64) { return m.value.Load() }
|