mirror of
https://github.com/redis/go-redis.git
synced 2025-12-02 06:22:31 +03:00
use sync.Cond
This commit is contained in:
@@ -185,7 +185,7 @@ type AutoPipeliner struct {
|
|||||||
queueLen atomic.Int32 // Fast path check without lock
|
queueLen atomic.Int32 // Fast path check without lock
|
||||||
|
|
||||||
// Flush control
|
// Flush control
|
||||||
flushCh chan struct{} // Signal to flush immediately
|
flushCond *sync.Cond // Condition variable to signal flusher
|
||||||
|
|
||||||
// Concurrency control
|
// Concurrency control
|
||||||
sem *internal.FastSemaphore // Semaphore for concurrent batch limit
|
sem *internal.FastSemaphore // Semaphore for concurrent batch limit
|
||||||
@@ -219,12 +219,15 @@ func NewAutoPipeliner(pipeliner cmdableClient, config *AutoPipelineConfig) *Auto
|
|||||||
ap := &AutoPipeliner{
|
ap := &AutoPipeliner{
|
||||||
pipeliner: pipeliner,
|
pipeliner: pipeliner,
|
||||||
config: config,
|
config: config,
|
||||||
flushCh: make(chan struct{}, 1),
|
|
||||||
sem: internal.NewFastSemaphore(int32(config.MaxConcurrentBatches)),
|
sem: internal.NewFastSemaphore(int32(config.MaxConcurrentBatches)),
|
||||||
ctx: ctx,
|
ctx: ctx,
|
||||||
cancel: cancel,
|
cancel: cancel,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Initialize condition variable for flush signaling
|
||||||
|
// Use a separate mutex for the condition variable to avoid contention with queue operations
|
||||||
|
ap.flushCond = sync.NewCond(&sync.Mutex{})
|
||||||
|
|
||||||
// Initialize cmdable to route all commands through processAndBlock
|
// Initialize cmdable to route all commands through processAndBlock
|
||||||
ap.cmdable = ap.processAndBlock
|
ap.cmdable = ap.processAndBlock
|
||||||
|
|
||||||
@@ -323,11 +326,8 @@ func (ap *AutoPipeliner) processWithQueuedCmd(ctx context.Context, cmd Cmder) *q
|
|||||||
ap.queueLen.Store(int32(queueLen))
|
ap.queueLen.Store(int32(queueLen))
|
||||||
ap.mu.Unlock()
|
ap.mu.Unlock()
|
||||||
|
|
||||||
// Always signal the flusher (non-blocking)
|
// Signal the flusher using condition variable
|
||||||
select {
|
ap.flushCond.Signal()
|
||||||
case ap.flushCh <- struct{}{}:
|
|
||||||
default:
|
|
||||||
}
|
|
||||||
return qc
|
return qc
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -338,11 +338,8 @@ func (ap *AutoPipeliner) processWithQueuedCmd(ctx context.Context, cmd Cmder) *q
|
|||||||
ap.queueLen.Store(int32(queueLen))
|
ap.queueLen.Store(int32(queueLen))
|
||||||
ap.mu.Unlock()
|
ap.mu.Unlock()
|
||||||
|
|
||||||
// always signal the flusher (non-blocking)
|
// Signal the flusher using condition variable
|
||||||
select {
|
ap.flushCond.Signal()
|
||||||
case ap.flushCh <- struct{}{}:
|
|
||||||
default:
|
|
||||||
}
|
|
||||||
return qc
|
return qc
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -360,6 +357,9 @@ func (ap *AutoPipeliner) Close() error {
|
|||||||
// Cancel context to stop flusher
|
// Cancel context to stop flusher
|
||||||
ap.cancel()
|
ap.cancel()
|
||||||
|
|
||||||
|
// Signal the flusher to wake up and check context
|
||||||
|
ap.flushCond.Signal()
|
||||||
|
|
||||||
// Wait for flusher to finish
|
// Wait for flusher to finish
|
||||||
ap.wg.Wait()
|
ap.wg.Wait()
|
||||||
|
|
||||||
@@ -372,30 +372,22 @@ func (ap *AutoPipeliner) Close() error {
|
|||||||
// flusher is the background goroutine that flushes batches.
|
// flusher is the background goroutine that flushes batches.
|
||||||
func (ap *AutoPipeliner) flusher() {
|
func (ap *AutoPipeliner) flusher() {
|
||||||
defer ap.wg.Done()
|
defer ap.wg.Done()
|
||||||
|
|
||||||
for {
|
for {
|
||||||
// Wait for a command to arrive
|
// Wait for a command to arrive using condition variable
|
||||||
select {
|
ap.flushCond.L.Lock()
|
||||||
case <-ap.flushCh:
|
for ap.Len() == 0 && ap.ctx.Err() == nil {
|
||||||
// Command arrived, continue
|
ap.flushCond.Wait()
|
||||||
case <-ap.ctx.Done():
|
}
|
||||||
|
ap.flushCond.L.Unlock()
|
||||||
|
|
||||||
|
// Check if context is cancelled
|
||||||
|
if ap.ctx.Err() != nil {
|
||||||
// Final flush before shutdown
|
// Final flush before shutdown
|
||||||
ap.flushBatchSlice()
|
ap.flushBatchSlice()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Drain any additional signals
|
|
||||||
for {
|
|
||||||
select {
|
|
||||||
case <-ap.flushCh:
|
|
||||||
if ap.Len() >= ap.config.MaxBatchSize {
|
|
||||||
goto drained
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
goto drained
|
|
||||||
}
|
|
||||||
}
|
|
||||||
drained:
|
|
||||||
|
|
||||||
// Flush all pending commands
|
// Flush all pending commands
|
||||||
for ap.Len() > 0 {
|
for ap.Len() > 0 {
|
||||||
select {
|
select {
|
||||||
|
|||||||
Reference in New Issue
Block a user