* ring: remove external rendezvous dependency by inlining implementation
Replace usage of github.com/dgryski/go-rendezvous with an internal
implementation to eliminate the external dependency and avoid licence
propagation concerns.
The implementation preserves the exact hashing algorithm and behaviour:
- same hash combination: khash ^ nhash
- same mixing function (xorshift* variant)
- same node ordering semantics
No functional changes intended.
* Refactor TestRendezvous to remove randomString function
Replaced function with inline string generation for test cases.
* test: refactor RendezvousHash tests to use Ginkgo and Gomega
* test: improve RendezvousHash test for per-instance determinism and distribution balance
* test: enhance distribution verification in RendezvousHash tests
* chore(go): update go version to 1.24
* update readmes and ci workflows
* update dockerfile for proxy-fi-server
* address changed test behaviour
* address changed test behaviour
* First draft. One metric - command duration.
Signed-off-by: Elena Kolevska <[email protected]>
* Adds connection state metrics
Signed-off-by: Elena Kolevska <[email protected]>
* wip
Signed-off-by: Elena Kolevska <[email protected]>
* Add phase 1 metrics
* Add client api configurations
* remove redundent code
* refactor: move otel-metrics example to separate module
* refactor: move otel-metrics example to separate module
* remove internal test
* Resolve merge conflicts with upstream/master
* Fix linting issues
* Fix pool idle connection counter bug
* Add OTel performance benchmarking suite
* Improve perf compatison script
* Add phase 2,3 metrics
* Remove local benchmark tests
* Add new fields to tests
* Change db.client.connection.count and db.client.connection.pending_request metric type from UpAndDownCounter to Async gauge.
* fix golangci lint
* Add piplined commands metrics support
* Redesign otel init method
* Address comments
* Fix golangci-lint errors
* Fix passing nil pointer
* Add metric prefix to callbacks and atomic batch registration
* Add unique name for pool.name attr
* Fix unique pool name for pubsub
* Refactor all hardcoded OTel attribute strings to use constants
* Refactor all hardcoded OTel attribute strings to use constants
* extract metric names and pool names as constants, improve error handling
---------
Signed-off-by: Elena Kolevska <[email protected]>
Co-authored-by: Elena Kolevska <[email protected]>
* chore(tests): add tls tests
* fix: Use ShardPicker for keyless commands instead of random slot
- cmdSlot now returns -1 for keyless commands instead of RandomSlot()
- This allows cmdNodeWithShardPicker to use the configured ShardPicker
(default: RoundRobinPicker) for keyless command routing
- Updated mapCmdsByNode to handle slot == -1 by using ShardPicker
- Updated test to verify round robin distribution works correctly
* chore(image): update clients-test-lib image
* chore(tests): enable tls user auth test
* chore(docker): use proper envs for test image
* chore(image): use latest build
* chore(image): use latest build
* fix(tests): use the correct root cert
* feat(tls): add example app
* chore(docker): address pr comments
* chore(tests): address pr comments
* chore(doc): add README.md in the example app
* fix(tests): do not skip tests
* fix(tests): skip only because of redis version
* Extracts default image name in a var (including osscluster-tls)
Signed-off-by: Elena Kolevska <[email protected]>
* fix(tlstests): remove redundent test
---------
Signed-off-by: Elena Kolevska <[email protected]>
Co-authored-by: Elena Kolevska <[email protected]>
* chore(go): update go version to 1.21
* chore(aggregators): make aggregators work with 1.21
* fix doctests
* address copilot comments
* use atomic bool for logic and/or aggregators
* Update .github/workflows/build.yml
Co-authored-by: ccoVeille <[email protected]>
* use stable/oldstable, 1.23 and 1.21
* fix versions in README
* add oldstable in wordlist
---------
Co-authored-by: ccoVeille <[email protected]>
* wip
* wip, used and unusable states
* polish state machine
* correct handling OnPut
* better errors for tests, hook should work now
* fix linter
* improve reauth state management. fix tests
* Update internal/pool/conn.go
Co-authored-by: Copilot <[email protected]>
* Update internal/pool/conn.go
Co-authored-by: Copilot <[email protected]>
* better timeouts
* empty endpoint handoff case
* fix handoff state when queued for handoff
* try to detect the deadlock
* try to detect the deadlock x2
* delete should be called
* improve tests
* fix mark on uninitialized connection
* Update internal/pool/conn_state_test.go
Co-authored-by: Copilot <[email protected]>
* Update internal/pool/conn_state_test.go
Co-authored-by: Copilot <[email protected]>
* Update internal/pool/pool.go
Co-authored-by: Copilot <[email protected]>
* Update internal/pool/conn_state.go
Co-authored-by: Copilot <[email protected]>
* Update internal/pool/conn.go
Co-authored-by: Copilot <[email protected]>
* fix error from copilot
* address copilot comment
* fix(pool): pool performance (#3565)
* perf(pool): replace hookManager RWMutex with atomic.Pointer and add predefined state slices
- Replace hookManager RWMutex with atomic.Pointer for lock-free reads in hot paths
- Add predefined state slices to avoid allocations (validFromInUse, validFromCreatedOrIdle, etc.)
- Add Clone() method to PoolHookManager for atomic updates
- Update AddPoolHook/RemovePoolHook to use copy-on-write pattern
- Update all hookManager access points to use atomic Load()
Performance improvements:
- Eliminates RWMutex contention in Get/Put/Remove hot paths
- Reduces allocations by reusing predefined state slices
- Lock-free reads allow better CPU cache utilization
* perf(pool): eliminate mutex overhead in state machine hot path
The state machine was calling notifyWaiters() on EVERY Get/Put operation,
which acquired a mutex even when no waiters were present (the common case).
Fix: Use atomic waiterCount to check for waiters BEFORE acquiring mutex.
This eliminates mutex contention in the hot path (Get/Put operations).
Implementation:
- Added atomic.Int32 waiterCount field to ConnStateMachine
- Increment when adding waiter, decrement when removing
- Check waiterCount atomically before acquiring mutex in notifyWaiters()
Performance impact:
- Before: mutex lock/unlock on every Get/Put (even with no waiters)
- After: lock-free atomic check, only acquire mutex if waiters exist
- Expected improvement: ~30-50% for Get/Put operations
* perf(pool): use predefined state slices to eliminate allocations in hot path
The pool was creating new slice literals on EVERY Get/Put operation:
- popIdle(): []ConnState{StateCreated, StateIdle}
- putConn(): []ConnState{StateInUse}
- CompareAndSwapUsed(): []ConnState{StateIdle} and []ConnState{StateInUse}
- MarkUnusableForHandoff(): []ConnState{StateInUse, StateIdle, StateCreated}
These allocations were happening millions of times per second in the hot path.
Fix: Use predefined global slices defined in conn_state.go:
- validFromInUse
- validFromCreatedOrIdle
- validFromCreatedInUseOrIdle
Performance impact:
- Before: 4 slice allocations per Get/Put cycle
- After: 0 allocations (use predefined slices)
- Expected improvement: ~30-40% reduction in allocations and GC pressure
* perf(pool): optimize TryTransition to reduce atomic operations
Further optimize the hot path by:
1. Remove redundant GetState() call in the loop
2. Only check waiterCount after successful CAS (not before loop)
3. Inline the waiterCount check to avoid notifyWaiters() call overhead
This reduces atomic operations from 4-5 per Get/Put to 2-3:
- Before: GetState() + CAS + waiterCount.Load() + notifyWaiters mutex check
- After: CAS + waiterCount.Load() (only if CAS succeeds)
Performance impact:
- Eliminates 1-2 atomic operations per Get/Put
- Expected improvement: ~10-15% for Get/Put operations
* perf(pool): add fast path for Get/Put to match master performance
Introduced TryTransitionFast() for the hot path (Get/Put operations):
- Single CAS operation (same as master's atomic bool)
- No waiter notification overhead
- No loop through valid states
- No error allocation
Hot path flow:
1. popIdle(): Try IDLE → IN_USE (fast), fallback to CREATED → IN_USE
2. putConn(): Try IN_USE → IDLE (fast)
This matches master's performance while preserving state machine for:
- Background operations (handoff/reauth use UNUSABLE state)
- State validation (TryTransition still available)
- Waiter notification (AwaitAndTransition for blocking)
Performance comparison per Get/Put cycle:
- Master: 2 atomic CAS operations
- State machine (before): 5 atomic operations (2.5x slower)
- State machine (after): 2 atomic CAS operations (same as master!)
Expected improvement: Restore to baseline ~11,373 ops/sec
* combine cas
* fix linter
* try faster approach
* fast semaphore
* better inlining for hot path
* fix linter issues
* use new semaphore in auth as well
* linter should be happy now
* add comments
* Update internal/pool/conn_state.go
Co-authored-by: Copilot <[email protected]>
* address comment
* slight reordering
* try to cache time if for non-critical calculation
* fix wrong benchmark
* add concurrent test
* fix benchmark report
* add additional expect to check output
* comment and variable rename
---------
Co-authored-by: Copilot <[email protected]>
* initConn sets IDLE state
- Handle unexpected conn state changes
* fix precision of time cache and usedAt
* allow e2e tests to run longer
* Fix broken initialization of idle connections
* optimize push notif
* 100ms -> 50ms
* use correct timer for last health check
* verify pass auth on conn creation
* fix assertion
* fix unsafe test
* fix benchmark test
* improve remove conn
* re doesn't support requirepass
* wait more in e2e test
* flaky test
* add missed method in interface
* fix test assertions
* silence logs and faster hooks manager
* address linter comment
* fix flaky test
* use read instad of control
* use pool size for semsize
* CAS instead of reading the state
* preallocate errors and states
* preallocate state slices
* fix flaky test
* fix fast semaphore that could have been starved
* try to fix the semaphore
* should properly notify the waiters
- this way a waiter that timesout at the same time
a releaser is releasing, won't throw token. the releaser
will fail to notify and will pick another waiter.
this hybrid approach should be faster than channels and maintains FIFO
* waiter may double-release (if closed/times out)
* priority of operations
* use simple approach of fifo waiters
* use simple channel based semaphores
* address linter and tests
* remove unused benchs
* change log message
* address pr comments
* address pr comments
* fix data race
---------
Co-authored-by: Copilot <[email protected]>
* add cas/cad commands
* feat(command): Add SetIFDEQ, SetIFDNE and *Get cmds
Decided to move the *Get argument as a separate methods, since the
response will be always the previous value, but in the case where
the previous value is `OK` there result may be ambiguous.
* fix tests
* matchValue to be interface{}
* Only Args approach for DelEx
* use uint64 for digest, add example
* test only for 8.4
- Adds support for handling push notifications with RESP3.
- Using this support adds handlers for hitless upgrades.
---------
Co-authored-by: Copilot <[email protected]>
Co-authored-by: Hristo Temelski <[email protected]>
* chore: extract benchmark tests
* wip
* enable pubsub tests
* enable ring tests
* stop tests with build redis from source
* start all tests
* mix of makefile and action
* add sentinel configs
* fix example test
* stop debug on re
* wip
* enable gears for redis 7.2
* wip
* enable sentinel, they are expected to fail
* fix: linter configuration
* chore: update re versions
* return older redis enterprise version
* add basic codeql
* wip: increase timeout, focus only sentinel tests
* sentinels with docker network host
* enable all tests
* fix flanky test
* enable example tests
* tidy docker compose
* add debug output
* stop shutingdown masters
* don't test sentinel for re
* skip unsuported addscores
* Update README
bump go version in CI
* Update README.md
Co-authored-by: Copilot <[email protected]>
* Update CONTRIBUTING.md
add information about new test setup
---------
Co-authored-by: Copilot <[email protected]>