mirror of
https://github.com/redis/go-redis.git
synced 2025-12-02 06:22:31 +03:00
Merge branch 'ndyakov/optional-logger' into optional-logger
This commit is contained in:
4
.github/workflows/build.yml
vendored
4
.github/workflows/build.yml
vendored
@@ -32,7 +32,7 @@ jobs:
|
||||
go-version: ${{ matrix.go-version }}
|
||||
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v5
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Setup Test environment
|
||||
env:
|
||||
@@ -83,7 +83,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v5
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Run tests
|
||||
uses: ./.github/actions/run-tests
|
||||
|
||||
2
.github/workflows/codeql-analysis.yml
vendored
2
.github/workflows/codeql-analysis.yml
vendored
@@ -35,7 +35,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v5
|
||||
uses: actions/checkout@v6
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
|
||||
2
.github/workflows/doctests.yaml
vendored
2
.github/workflows/doctests.yaml
vendored
@@ -36,7 +36,7 @@ jobs:
|
||||
go-version: ${{ matrix.go-version }}
|
||||
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v5
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Test doc examples
|
||||
working-directory: ./doctests
|
||||
|
||||
4
.github/workflows/golangci-lint.yml
vendored
4
.github/workflows/golangci-lint.yml
vendored
@@ -20,9 +20,9 @@ jobs:
|
||||
name: lint
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
- uses: actions/checkout@v6
|
||||
- name: golangci-lint
|
||||
uses: golangci/golangci-lint-action@v9.0.0
|
||||
uses: golangci/golangci-lint-action@v9.1.0
|
||||
with:
|
||||
verify: true
|
||||
|
||||
|
||||
2
.github/workflows/spellcheck.yml
vendored
2
.github/workflows/spellcheck.yml
vendored
@@ -6,7 +6,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v5
|
||||
uses: actions/checkout@v6
|
||||
- name: Check Spelling
|
||||
uses: rojopolis/spellcheck-github-actions@0.54.0
|
||||
with:
|
||||
|
||||
4
.github/workflows/test-redis-enterprise.yml
vendored
4
.github/workflows/test-redis-enterprise.yml
vendored
@@ -20,10 +20,10 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v5
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Clone Redis EE docker repository
|
||||
uses: actions/checkout@v5
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
repository: RedisLabs/redis-ee-docker
|
||||
path: redis-ee
|
||||
|
||||
@@ -64,6 +64,7 @@ var keylessCommands = map[string]struct{}{
|
||||
"sync": {},
|
||||
"unsubscribe": {},
|
||||
"unwatch": {},
|
||||
"wait": {},
|
||||
}
|
||||
|
||||
type Cmder interface {
|
||||
|
||||
@@ -27,16 +27,17 @@ var (
|
||||
errConnNotAvailableForWrite = errors.New("redis: connection not available for write operation")
|
||||
)
|
||||
|
||||
// getCachedTimeNs returns the current time in nanoseconds from the global cache.
|
||||
// This is updated every 50ms by a background goroutine, avoiding expensive syscalls.
|
||||
// Max staleness: 50ms.
|
||||
// getCachedTimeNs returns the current time in nanoseconds.
|
||||
// This function previously used a global cache updated by a background goroutine,
|
||||
// but that caused unnecessary CPU usage when the client was idle (ticker waking up
|
||||
// the scheduler every 50ms). We now use time.Now() directly, which is fast enough
|
||||
// on modern systems (vDSO on Linux) and only adds ~1-2% overhead in extreme
|
||||
// high-concurrency benchmarks while eliminating idle CPU usage.
|
||||
func getCachedTimeNs() int64 {
|
||||
return globalTimeCache.nowNs.Load()
|
||||
return time.Now().UnixNano()
|
||||
}
|
||||
|
||||
// GetCachedTimeNs returns the current time in nanoseconds from the global cache.
|
||||
// This is updated every 50ms by a background goroutine, avoiding expensive syscalls.
|
||||
// Max staleness: 50ms.
|
||||
// GetCachedTimeNs returns the current time in nanoseconds.
|
||||
// Exported for use by other packages that need fast time access.
|
||||
func GetCachedTimeNs() int64 {
|
||||
return getCachedTimeNs()
|
||||
|
||||
@@ -1,74 +0,0 @@
|
||||
package pool
|
||||
|
||||
import (
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Global time cache updated every 50ms by background goroutine.
|
||||
// This avoids expensive time.Now() syscalls in hot paths like getEffectiveReadTimeout.
|
||||
// Max staleness: 50ms, which is acceptable for timeout deadline checks (timeouts are typically 3-30 seconds).
|
||||
var globalTimeCache struct {
|
||||
nowNs atomic.Int64
|
||||
lock sync.Mutex
|
||||
started bool
|
||||
stop chan struct{}
|
||||
subscribers int32
|
||||
}
|
||||
|
||||
func subscribeToGlobalTimeCache() {
|
||||
globalTimeCache.lock.Lock()
|
||||
globalTimeCache.subscribers += 1
|
||||
globalTimeCache.lock.Unlock()
|
||||
}
|
||||
|
||||
func unsubscribeFromGlobalTimeCache() {
|
||||
globalTimeCache.lock.Lock()
|
||||
globalTimeCache.subscribers -= 1
|
||||
globalTimeCache.lock.Unlock()
|
||||
}
|
||||
|
||||
func startGlobalTimeCache() {
|
||||
globalTimeCache.lock.Lock()
|
||||
if globalTimeCache.started {
|
||||
globalTimeCache.lock.Unlock()
|
||||
return
|
||||
}
|
||||
|
||||
globalTimeCache.started = true
|
||||
globalTimeCache.nowNs.Store(time.Now().UnixNano())
|
||||
globalTimeCache.stop = make(chan struct{})
|
||||
globalTimeCache.lock.Unlock()
|
||||
// Start background updater
|
||||
go func(stopChan chan struct{}) {
|
||||
ticker := time.NewTicker(50 * time.Millisecond)
|
||||
defer ticker.Stop()
|
||||
|
||||
for range ticker.C {
|
||||
select {
|
||||
case <-stopChan:
|
||||
return
|
||||
default:
|
||||
}
|
||||
globalTimeCache.nowNs.Store(time.Now().UnixNano())
|
||||
}
|
||||
}(globalTimeCache.stop)
|
||||
}
|
||||
|
||||
// stopGlobalTimeCache stops the global time cache if there are no subscribers.
|
||||
// This should only be called when the last subscriber is removed.
|
||||
func stopGlobalTimeCache() {
|
||||
globalTimeCache.lock.Lock()
|
||||
if !globalTimeCache.started || globalTimeCache.subscribers > 0 {
|
||||
globalTimeCache.lock.Unlock()
|
||||
return
|
||||
}
|
||||
globalTimeCache.started = false
|
||||
close(globalTimeCache.stop)
|
||||
globalTimeCache.lock.Unlock()
|
||||
}
|
||||
|
||||
func init() {
|
||||
startGlobalTimeCache()
|
||||
}
|
||||
@@ -182,9 +182,6 @@ func NewConnPool(opt *Options) *ConnPool {
|
||||
p.connsMu.Unlock()
|
||||
}
|
||||
|
||||
startGlobalTimeCache()
|
||||
subscribeToGlobalTimeCache()
|
||||
|
||||
return p
|
||||
}
|
||||
|
||||
@@ -985,9 +982,6 @@ func (p *ConnPool) Close() error {
|
||||
return ErrClosed
|
||||
}
|
||||
|
||||
unsubscribeFromGlobalTimeCache()
|
||||
stopGlobalTimeCache()
|
||||
|
||||
var firstErr error
|
||||
p.connsMu.Lock()
|
||||
for _, cn := range p.conns {
|
||||
|
||||
@@ -4,9 +4,25 @@ set -e
|
||||
|
||||
DRY_RUN=1
|
||||
|
||||
helps() {
|
||||
cat <<- EOF
|
||||
Usage: $0 TAGVERSION [-t]
|
||||
|
||||
Creates git tags for public Go packages.
|
||||
|
||||
ARGUMENTS:
|
||||
TAGVERSION Tag version to create, for example v1.0.0
|
||||
|
||||
OPTIONS:
|
||||
-t Execute git commands (default: dry run)
|
||||
EOF
|
||||
exit 0
|
||||
}
|
||||
|
||||
|
||||
if [ $# -eq 0 ]; then
|
||||
echo "Error: Tag version is required"
|
||||
help
|
||||
helps
|
||||
fi
|
||||
|
||||
TAG=$1
|
||||
@@ -24,20 +40,6 @@ while getopts "t" opt; do
|
||||
esac
|
||||
done
|
||||
|
||||
help() {
|
||||
cat <<- EOF
|
||||
Usage: $0 TAGVERSION [-t]
|
||||
|
||||
Creates git tags for public Go packages.
|
||||
|
||||
ARGUMENTS:
|
||||
TAGVERSION Tag version to create, for example v1.0.0
|
||||
|
||||
OPTIONS:
|
||||
-t Execute git commands (default: dry run)
|
||||
EOF
|
||||
exit 0
|
||||
}
|
||||
|
||||
if [ "$DRY_RUN" -eq 1 ]; then
|
||||
echo "Running in dry-run mode"
|
||||
|
||||
Reference in New Issue
Block a user