@@ -85,8 +85,7 @@ type pipe struct {
85
85
_ [10 ]int32
86
86
blcksig int32
87
87
state int32
88
- waits int32
89
- recvs int32
88
+ wrCounter atomic.Uint64
90
89
bgState int32
91
90
r2ps bool // identify this pipe is used for resp2 pubsub or not
92
91
noNoDelay bool
@@ -372,10 +371,10 @@ func (p *pipe) _background() {
372
371
select {
373
372
case <- p .close :
374
373
default :
375
- atomic . AddInt32 ( & p . waits , 1 )
374
+ p . incrWaits ( )
376
375
go func () {
377
376
<- p .queue .PutOne (cmds .PingCmd ) // avoid _backgroundWrite hanging at p.queue.WaitForWrite()
378
- atomic . AddInt32 ( & p . waits , - 1 )
377
+ p . decrWaits ( )
379
378
}()
380
379
}
381
380
}
@@ -406,7 +405,7 @@ func (p *pipe) _background() {
406
405
}
407
406
408
407
resp := newErrResult (err )
409
- for atomic . LoadInt32 ( & p . waits ) != 0 {
408
+ for p . loadWaits ( ) != 0 {
410
409
select {
411
410
case <- p .close : // p.queue.NextWriteCmd() can only be called after _backgroundWrite
412
411
_ , _ , _ = p .queue .NextWriteCmd ()
@@ -450,7 +449,7 @@ func (p *pipe) _backgroundWrite() (err error) {
450
449
}
451
450
}
452
451
ones [0 ], multi , ch = p .queue .WaitForWrite ()
453
- if flushDelay != 0 && atomic . LoadInt32 ( & p . waits ) > 1 { // do not delay for sequential usage
452
+ if flushDelay != 0 && p . loadWaits ( ) > 1 { // do not delay for sequential usage
454
453
// Blocking commands are executed in dedicated client which is acquired from pool.
455
454
// So, there is no sense to wait other commands to be written.
456
455
// https://github.com/redis/rueidis/issues/379
@@ -637,17 +636,17 @@ func (p *pipe) _backgroundRead() (err error) {
637
636
func (p * pipe ) backgroundPing () {
638
637
var prev , recv int32
639
638
640
- prev = atomic . LoadInt32 ( & p . recvs )
639
+ prev = p . loadRecvs ( )
641
640
p .pingTimer = time .AfterFunc (p .pinggap , func () {
642
641
var err error
643
- recv = atomic . LoadInt32 ( & p . recvs )
642
+ recv = p . loadRecvs ( )
644
643
defer func () {
645
644
if err == nil && p .Error () == nil {
646
- prev = atomic . LoadInt32 ( & p . recvs )
645
+ prev = p . loadRecvs ( )
647
646
p .pingTimer .Reset (p .pinggap )
648
647
}
649
648
}()
650
- if recv != prev || atomic .LoadInt32 (& p .blcksig ) != 0 || (atomic .LoadInt32 (& p .state ) == 0 && atomic . LoadInt32 ( & p . waits ) != 0 ) {
649
+ if recv != prev || atomic .LoadInt32 (& p .blcksig ) != 0 || (atomic .LoadInt32 (& p .state ) == 0 && p . loadWaits ( ) != 0 ) {
651
650
return
652
651
}
653
652
ch := make (chan error , 1 )
@@ -840,10 +839,10 @@ func (p *pipe) SetPubSubHooks(hooks PubSubHooks) <-chan error {
840
839
close (old .close )
841
840
}
842
841
}
843
- if atomic . AddInt32 ( & p . waits , 1 ) == 1 && atomic .LoadInt32 (& p .state ) == 0 {
842
+ if p . incrWaits ( ) == 1 && atomic .LoadInt32 (& p .state ) == 0 {
844
843
p .background ()
845
844
}
846
- atomic . AddInt32 ( & p . waits , - 1 )
845
+ p . decrWaits ( )
847
846
return ch
848
847
}
849
848
@@ -884,7 +883,7 @@ func (p *pipe) Do(ctx context.Context, cmd Completed) (resp RedisResult) {
884
883
return p ._r2pipe (ctx ).Do (ctx , cmd )
885
884
}
886
885
}
887
- waits := atomic . AddInt32 ( & p . waits , 1 ) // if this is 1, and background worker is not started, no need to queue
886
+ waits := p . incrWaits ( ) // if this is 1, and background worker is not started, no need to queue
888
887
state := atomic .LoadInt32 (& p .state )
889
888
890
889
if state == 1 {
@@ -908,10 +907,10 @@ func (p *pipe) Do(ctx context.Context, cmd Completed) (resp RedisResult) {
908
907
} else {
909
908
resp = newErrResult (p .Error ())
910
909
}
911
- if left := atomic .AddInt32 (& p .waits , - 1 ); state == 0 && left != 0 {
910
+
911
+ if _ , left := p .decrWaitsAndIncrRecvs (); state == 0 && left != 0 {
912
912
p .background ()
913
913
}
914
- atomic .AddInt32 (& p .recvs , 1 )
915
914
return resp
916
915
917
916
queue:
@@ -925,14 +924,12 @@ queue:
925
924
goto abort
926
925
}
927
926
}
928
- atomic .AddInt32 (& p .waits , - 1 )
929
- atomic .AddInt32 (& p .recvs , 1 )
927
+ p .decrWaitsAndIncrRecvs ()
930
928
return resp
931
929
abort:
932
930
go func (ch chan RedisResult ) {
933
931
<- ch
934
- atomic .AddInt32 (& p .waits , - 1 )
935
- atomic .AddInt32 (& p .recvs , 1 )
932
+ p .decrWaitsAndIncrRecvs ()
936
933
}(ch )
937
934
return newErrResult (ctx .Err ())
938
935
}
@@ -990,7 +987,7 @@ func (p *pipe) DoMulti(ctx context.Context, multi ...Completed) *redisresults {
990
987
}
991
988
}
992
989
993
- waits := atomic . AddInt32 ( & p . waits , 1 ) // if this is 1, and background worker is not started, no need to queue
990
+ waits := p . incrWaits ( ) // if this is 1, and background worker is not started, no need to queue
994
991
state := atomic .LoadInt32 (& p .state )
995
992
996
993
if state == 1 {
@@ -1017,10 +1014,9 @@ func (p *pipe) DoMulti(ctx context.Context, multi ...Completed) *redisresults {
1017
1014
resp .s [i ] = err
1018
1015
}
1019
1016
}
1020
- if left := atomic . AddInt32 ( & p . waits , - 1 ); state == 0 && left != 0 {
1017
+ if _ , left := p . decrWaitsAndIncrRecvs ( ); state == 0 && left != 0 {
1021
1018
p .background ()
1022
1019
}
1023
- atomic .AddInt32 (& p .recvs , 1 )
1024
1020
return resp
1025
1021
1026
1022
queue:
@@ -1034,15 +1030,13 @@ queue:
1034
1030
goto abort
1035
1031
}
1036
1032
}
1037
- atomic .AddInt32 (& p .waits , - 1 )
1038
- atomic .AddInt32 (& p .recvs , 1 )
1033
+ p .decrWaitsAndIncrRecvs ()
1039
1034
return resp
1040
1035
abort:
1041
1036
go func (resp * redisresults , ch chan RedisResult ) {
1042
1037
<- ch
1043
1038
resultsp .Put (resp )
1044
- atomic .AddInt32 (& p .waits , - 1 )
1045
- atomic .AddInt32 (& p .recvs , 1 )
1039
+ p .decrWaitsAndIncrRecvs ()
1046
1040
}(resp , ch )
1047
1041
resp = resultsp .Get (len (multi ), len (multi ))
1048
1042
err := newErrResult (ctx .Err ())
@@ -1084,7 +1078,7 @@ func (s *RedisResultStream) WriteTo(w io.Writer) (n int64, err error) {
1084
1078
}
1085
1079
if s .n -- ; s .n == 0 {
1086
1080
atomic .AddInt32 (& s .w .blcksig , - 1 )
1087
- atomic . AddInt32 ( & s .w .waits , - 1 )
1081
+ s .w .decrWaits ( )
1088
1082
if s .e == nil {
1089
1083
s .e = io .EOF
1090
1084
} else {
@@ -1111,7 +1105,7 @@ func (p *pipe) DoStream(ctx context.Context, pool *pool, cmd Completed) RedisRes
1111
1105
1112
1106
if state == 0 {
1113
1107
atomic .AddInt32 (& p .blcksig , 1 )
1114
- waits := atomic . AddInt32 ( & p . waits , 1 )
1108
+ waits := p . incrWaits ( )
1115
1109
if waits != 1 {
1116
1110
panic ("DoStream with racing is a bug" )
1117
1111
}
@@ -1139,7 +1133,7 @@ func (p *pipe) DoStream(ctx context.Context, pool *pool, cmd Completed) RedisRes
1139
1133
}
1140
1134
}
1141
1135
atomic .AddInt32 (& p .blcksig , - 1 )
1142
- atomic . AddInt32 ( & p . waits , - 1 )
1136
+ p . decrWaits ( )
1143
1137
pool .Store (p )
1144
1138
return RedisResultStream {e : p .Error ()}
1145
1139
}
@@ -1161,7 +1155,7 @@ func (p *pipe) DoMultiStream(ctx context.Context, pool *pool, multi ...Completed
1161
1155
1162
1156
if state == 0 {
1163
1157
atomic .AddInt32 (& p .blcksig , 1 )
1164
- waits := atomic . AddInt32 ( & p . waits , 1 )
1158
+ waits := p . incrWaits ( )
1165
1159
if waits != 1 {
1166
1160
panic ("DoMultiStream with racing is a bug" )
1167
1161
}
@@ -1204,7 +1198,7 @@ func (p *pipe) DoMultiStream(ctx context.Context, pool *pool, multi ...Completed
1204
1198
}
1205
1199
}
1206
1200
atomic .AddInt32 (& p .blcksig , - 1 )
1207
- atomic . AddInt32 ( & p . waits , - 1 )
1201
+ p . decrWaits ( )
1208
1202
pool .Store (p )
1209
1203
return RedisResultStream {e : p .Error ()}
1210
1204
}
@@ -1559,6 +1553,36 @@ func (p *pipe) DoMultiCache(ctx context.Context, multi ...CacheableTTL) *redisre
1559
1553
return results
1560
1554
}
1561
1555
1556
+ // incrWaits increments the lower 32 bits (waits).
1557
+ func (p * pipe ) incrWaits () uint32 {
1558
+ // Increment the lower 32 bits (waits)
1559
+ return uint32 (p .wrCounter .Add (1 ))
1560
+ }
1561
+
1562
+ // decrWaits decrements the lower 32 bits (waits).
1563
+ func (p * pipe ) decrWaits () uint32 {
1564
+ // Decrement the lower 32 bits (waits)
1565
+ return uint32 (p .wrCounter .Add (^ uint64 (0 )) & 0xFFFFFFFF )
1566
+ }
1567
+
1568
+ // decrWaitsAndIncrRecvs decrements the lower 32 bits (waits) and increments the upper 32 bits (recvs).
1569
+ func (p * pipe ) decrWaitsAndIncrRecvs () (uint32 , uint32 ) {
1570
+ newValue := p .wrCounter .Add ((1 << 32 ) - 1 )
1571
+ return uint32 (newValue >> 32 ), uint32 (newValue & 0xFFFFFFFF )
1572
+ }
1573
+
1574
+ // loadRecvs loads the upper 32 bits (recvs).
1575
+ func (p * pipe ) loadRecvs () int32 {
1576
+ // Load the upper 32 bits (recvs)
1577
+ return int32 (p .wrCounter .Load () >> 32 )
1578
+ }
1579
+
1580
+ // loadWaits loads the lower 32 bits (waits).
1581
+ func (p * pipe ) loadWaits () uint32 {
1582
+ // Load the lower 32 bits (waits)
1583
+ return uint32 (p .wrCounter .Load () & 0xFFFFFFFF )
1584
+ }
1585
+
1562
1586
func (p * pipe ) Error () error {
1563
1587
if err := p .error .Load (); err != nil {
1564
1588
return err .error
@@ -1569,28 +1593,28 @@ func (p *pipe) Error() error {
1569
1593
func (p * pipe ) Close () {
1570
1594
p .error .CompareAndSwap (nil , errClosing )
1571
1595
block := atomic .AddInt32 (& p .blcksig , 1 )
1572
- waits := atomic . AddInt32 ( & p . waits , 1 )
1596
+ waits := p . incrWaits ( )
1573
1597
stopping1 := atomic .CompareAndSwapInt32 (& p .state , 0 , 2 )
1574
1598
stopping2 := atomic .CompareAndSwapInt32 (& p .state , 1 , 2 )
1575
1599
if p .queue != nil {
1576
1600
if stopping1 && waits == 1 { // make sure there is no sync read
1577
1601
p .background ()
1578
1602
}
1579
1603
if block == 1 && (stopping1 || stopping2 ) { // make sure there is no block cmd
1580
- atomic . AddInt32 ( & p . waits , 1 )
1604
+ p . incrWaits ( )
1581
1605
ch := p .queue .PutOne (cmds .PingCmd )
1582
1606
select {
1583
1607
case <- ch :
1584
- atomic . AddInt32 ( & p . waits , - 1 )
1608
+ p . decrWaits ( )
1585
1609
case <- time .After (time .Second ):
1586
1610
go func (ch chan RedisResult ) {
1587
1611
<- ch
1588
- atomic . AddInt32 ( & p . waits , - 1 )
1612
+ p . decrWaits ( )
1589
1613
}(ch )
1590
1614
}
1591
1615
}
1592
1616
}
1593
- atomic . AddInt32 ( & p . waits , - 1 )
1617
+ p . decrWaits ( )
1594
1618
atomic .AddInt32 (& p .blcksig , - 1 )
1595
1619
if p .pingTimer != nil {
1596
1620
p .pingTimer .Stop ()
0 commit comments