1
0
mirror of https://github.com/redis/go-redis.git synced 2025-12-02 06:22:31 +03:00
This commit is contained in:
Nedyalko Dyakov
2025-11-03 00:14:24 +02:00
parent ffa32a5370
commit c637c0824e
11 changed files with 1280 additions and 30 deletions

234
pipeline_buffer_test.go Normal file
View File

@@ -0,0 +1,234 @@
package redis_test
import (
"context"
"testing"
"github.com/redis/go-redis/v9"
)
// TestPipelineBufferSizes verifies that pipeline pool is created with custom buffer sizes
func TestPipelineBufferSizes(t *testing.T) {
ctx := context.Background()
// Create client with custom pipeline buffer sizes
client := redis.NewClient(&redis.Options{
Addr: "localhost:6379",
ReadBufferSize: 64 * 1024, // 64 KiB for regular connections
WriteBufferSize: 64 * 1024, // 64 KiB for regular connections
PipelineReadBufferSize: 512 * 1024, // 512 KiB for pipeline connections
PipelineWriteBufferSize: 512 * 1024, // 512 KiB for pipeline connections
PipelinePoolSize: 5, // Small pool for pipelining
})
defer client.Close()
// Test that regular commands work
err := client.Set(ctx, "test_key", "test_value", 0).Err()
if err != nil {
t.Fatalf("Failed to set key: %v", err)
}
val, err := client.Get(ctx, "test_key").Result()
if err != nil {
t.Fatalf("Failed to get key: %v", err)
}
if val != "test_value" {
t.Fatalf("Expected 'test_value', got '%s'", val)
}
// Test that pipeline works
pipe := client.Pipeline()
pipe.Set(ctx, "pipe_key1", "value1", 0)
pipe.Set(ctx, "pipe_key2", "value2", 0)
pipe.Get(ctx, "pipe_key1")
pipe.Get(ctx, "pipe_key2")
cmds, err := pipe.Exec(ctx)
if err != nil {
t.Fatalf("Pipeline execution failed: %v", err)
}
if len(cmds) != 4 {
t.Fatalf("Expected 4 commands, got %d", len(cmds))
}
// Verify results
if cmds[2].(*redis.StringCmd).Val() != "value1" {
t.Fatalf("Expected 'value1', got '%s'", cmds[2].(*redis.StringCmd).Val())
}
if cmds[3].(*redis.StringCmd).Val() != "value2" {
t.Fatalf("Expected 'value2', got '%s'", cmds[3].(*redis.StringCmd).Val())
}
t.Log("Pipeline with custom buffer sizes works correctly")
}
// TestPipelineBufferSizesWithAutoPipeline verifies that autopipeline uses the pipeline pool
func TestPipelineBufferSizesWithAutoPipeline(t *testing.T) {
ctx := context.Background()
// Create client with custom pipeline buffer sizes
client := redis.NewClient(&redis.Options{
Addr: "localhost:6379",
ReadBufferSize: 64 * 1024, // 64 KiB for regular connections
WriteBufferSize: 64 * 1024, // 64 KiB for regular connections
PipelineReadBufferSize: 512 * 1024, // 512 KiB for pipeline connections
PipelineWriteBufferSize: 512 * 1024, // 512 KiB for pipeline connections
PipelinePoolSize: 5, // Small pool for pipelining
AutoPipelineConfig: &redis.AutoPipelineConfig{
MaxBatchSize: 10,
MaxConcurrentBatches: 2,
UseRingBuffer: true,
RingBufferSize: 64,
},
})
defer client.Close()
// Test autopipeline
ap := client.AutoPipeline()
defer ap.Close()
// Send multiple commands
for i := 0; i < 20; i++ {
key := "ap_key_" + string(rune('0'+i%10))
val := "value_" + string(rune('0'+i%10))
ap.Set(ctx, key, val, 0).Err()
}
// Verify some values
val, err := client.Get(ctx, "ap_key_0").Result()
if err != nil {
t.Fatalf("Failed to get autopipelined key: %v", err)
}
if val != "value_0" {
t.Fatalf("Expected 'value_0', got '%s'", val)
}
t.Log("AutoPipeline with custom buffer sizes works correctly")
}
// TestNoPipelinePool verifies that client works without pipeline pool (backward compatibility)
func TestNoPipelinePool(t *testing.T) {
ctx := context.Background()
// Create client WITHOUT custom pipeline buffer sizes
client := redis.NewClient(&redis.Options{
Addr: "localhost:6379",
ReadBufferSize: 64 * 1024, // 64 KiB for all connections
WriteBufferSize: 64 * 1024, // 64 KiB for all connections
// No PipelineReadBufferSize or PipelineWriteBufferSize
})
defer client.Close()
// Test that pipeline still works (using regular pool)
pipe := client.Pipeline()
pipe.Set(ctx, "no_pipe_pool_key1", "value1", 0)
pipe.Set(ctx, "no_pipe_pool_key2", "value2", 0)
pipe.Get(ctx, "no_pipe_pool_key1")
pipe.Get(ctx, "no_pipe_pool_key2")
cmds, err := pipe.Exec(ctx)
if err != nil {
t.Fatalf("Pipeline execution failed: %v", err)
}
if len(cmds) != 4 {
t.Fatalf("Expected 4 commands, got %d", len(cmds))
}
// Verify results
if cmds[2].(*redis.StringCmd).Val() != "value1" {
t.Fatalf("Expected 'value1', got '%s'", cmds[2].(*redis.StringCmd).Val())
}
if cmds[3].(*redis.StringCmd).Val() != "value2" {
t.Fatalf("Expected 'value2', got '%s'", cmds[3].(*redis.StringCmd).Val())
}
t.Log("Pipeline without custom buffer sizes (backward compatibility) works correctly")
}
// TestPipelinePoolStats verifies that PoolStats includes pipeline pool stats
func TestPipelinePoolStats(t *testing.T) {
ctx := context.Background()
// Create client with custom pipeline buffer sizes
client := redis.NewClient(&redis.Options{
Addr: "localhost:6379",
ReadBufferSize: 64 * 1024, // 64 KiB for regular connections
WriteBufferSize: 64 * 1024, // 64 KiB for regular connections
PipelineReadBufferSize: 512 * 1024, // 512 KiB for pipeline connections
PipelineWriteBufferSize: 512 * 1024, // 512 KiB for pipeline connections
PipelinePoolSize: 5, // Small pool for pipelining
})
defer client.Close()
// Execute some pipeline commands
pipe := client.Pipeline()
for i := 0; i < 10; i++ {
pipe.Set(ctx, "stats_key", "value", 0)
}
_, err := pipe.Exec(ctx)
if err != nil {
t.Fatalf("Pipeline execution failed: %v", err)
}
// Get pool stats
stats := client.PoolStats()
if stats == nil {
t.Fatal("PoolStats returned nil")
}
// Verify pipeline stats are included
if stats.PipelineStats == nil {
t.Fatal("PipelineStats is nil - pipeline pool stats not included")
}
t.Logf("Regular pool stats: TotalConns=%d, IdleConns=%d, Hits=%d, Misses=%d",
stats.TotalConns, stats.IdleConns, stats.Hits, stats.Misses)
t.Logf("Pipeline pool stats: TotalConns=%d, IdleConns=%d, Hits=%d, Misses=%d",
stats.PipelineStats.TotalConns, stats.PipelineStats.IdleConns,
stats.PipelineStats.Hits, stats.PipelineStats.Misses)
// Verify pipeline pool has connections
if stats.PipelineStats.TotalConns == 0 {
t.Error("Pipeline pool has no connections")
}
t.Log("PoolStats includes pipeline pool stats correctly")
}
// TestNoPipelinePoolStats verifies that PoolStats works without pipeline pool
func TestNoPipelinePoolStats(t *testing.T) {
ctx := context.Background()
// Create client WITHOUT custom pipeline buffer sizes
client := redis.NewClient(&redis.Options{
Addr: "localhost:6379",
ReadBufferSize: 64 * 1024, // 64 KiB for all connections
WriteBufferSize: 64 * 1024, // 64 KiB for all connections
})
defer client.Close()
// Execute some commands
err := client.Set(ctx, "test_key", "test_value", 0).Err()
if err != nil {
t.Fatalf("Failed to set key: %v", err)
}
// Get pool stats
stats := client.PoolStats()
if stats == nil {
t.Fatal("PoolStats returned nil")
}
// Verify pipeline stats are nil (no pipeline pool)
if stats.PipelineStats != nil {
t.Error("PipelineStats should be nil when no pipeline pool is configured")
}
t.Logf("Regular pool stats: TotalConns=%d, IdleConns=%d, Hits=%d, Misses=%d",
stats.TotalConns, stats.IdleConns, stats.Hits, stats.Misses)
t.Log("PoolStats works correctly without pipeline pool")
}