@@ -1185,6 +1185,8 @@ func (c *grpcStorageClient) NewMultiRangeDownloader(ctx context.Context, params
1185
1185
done : false ,
1186
1186
activeTask : 0 ,
1187
1187
streamRecreation : false ,
1188
+ endReceiver : false ,
1189
+ endSender : false ,
1188
1190
}
1189
1191
1190
1192
// streamManager goroutine runs in background where we send message to gcs and process response.
@@ -1195,18 +1197,21 @@ func (c *grpcStorageClient) NewMultiRangeDownloader(ctx context.Context, params
1195
1197
case <- rr .ctx .Done ():
1196
1198
rr .mu .Lock ()
1197
1199
rr .done = true
1200
+ rr .endSender = true
1201
+ if rr .stream != nil {
1202
+ rr .stream .CloseSend ()
1203
+ }
1198
1204
rr .mu .Unlock ()
1199
1205
return
1200
1206
case <- rr .managerRetry :
1207
+ // We are not closing stream here as it is already closed and we are retring it.
1201
1208
return
1202
1209
case <- rr .closeManager :
1203
1210
rr .mu .Lock ()
1204
- if len (rr .mp ) != 0 {
1205
- for key := range rr .mp {
1206
- rr .mp [key ].callback (rr .mp [key ].offset , rr .mp [key ].totalBytesWritten , fmt .Errorf ("stream closed early" ))
1207
- delete (rr .mp , key )
1208
- }
1211
+ if rr .stream != nil {
1212
+ rr .stream .CloseSend ()
1209
1213
}
1214
+ rr .endSender = true
1210
1215
rr .activeTask = 0
1211
1216
rr .mu .Unlock ()
1212
1217
return
@@ -1255,11 +1260,29 @@ func (c *grpcStorageClient) NewMultiRangeDownloader(ctx context.Context, params
1255
1260
for {
1256
1261
select {
1257
1262
case <- rr .ctx .Done ():
1263
+ rr .mu .Lock ()
1264
+ rr .endReceiver = true
1258
1265
rr .done = true
1266
+ if len (rr .mp ) != 0 {
1267
+ drainInboundReadStream (rr .stream )
1268
+ }
1269
+ for key := range rr .mp {
1270
+ rr .mp [key ].callback (rr .mp [key ].offset , rr .mp [key ].totalBytesWritten , rr .ctx .Err ())
1271
+ delete (rr .mp , key )
1272
+ }
1273
+ rr .activeTask = 0
1274
+ rr .mu .Unlock ()
1259
1275
return
1260
1276
case <- rr .receiverRetry :
1277
+ // We are not draining from stream here as it is already closed and we are retring it.
1261
1278
return
1262
1279
case <- rr .closeReceiver :
1280
+ rr .mu .Lock ()
1281
+ if len (rr .mp ) != 0 {
1282
+ drainInboundReadStream (rr .stream )
1283
+ }
1284
+ rr .endReceiver = true
1285
+ rr .mu .Unlock ()
1263
1286
return
1264
1287
default :
1265
1288
// This function reads the data sent for a particular range request and has a callback
@@ -1269,7 +1292,9 @@ func (c *grpcStorageClient) NewMultiRangeDownloader(ctx context.Context, params
1269
1292
rr .readHandle = resp .GetReadHandle ().GetHandle ()
1270
1293
}
1271
1294
if err == io .EOF {
1272
- err = nil
1295
+ rr .mu .Lock ()
1296
+ rr .endReceiver = true
1297
+ rr .mu .Unlock ()
1273
1298
}
1274
1299
if err != nil {
1275
1300
// cancel stream and reopen the stream again.
@@ -1341,6 +1366,8 @@ func (c *grpcStorageClient) NewMultiRangeDownloader(ctx context.Context, params
1341
1366
err = rr .retryStream (err )
1342
1367
if err != nil {
1343
1368
rr .mu .Lock ()
1369
+ rr .endReceiver = true
1370
+ rr .endSender = true
1344
1371
for key := range rr .mp {
1345
1372
rr .mp [key ].callback (rr .mp [key ].offset , rr .mp [key ].totalBytesWritten , err )
1346
1373
delete (rr .mp , key )
@@ -1350,6 +1377,10 @@ func (c *grpcStorageClient) NewMultiRangeDownloader(ctx context.Context, params
1350
1377
rr .mu .Unlock ()
1351
1378
rr .close ()
1352
1379
} else {
1380
+ rr .mu .Lock ()
1381
+ rr .endReceiver = false
1382
+ rr .endSender = false
1383
+ rr .mu .Unlock ()
1353
1384
// If stream recreation happened successfully lets again start
1354
1385
// both the goroutine making the whole flow asynchronous again.
1355
1386
if thread == "receiver" {
@@ -1483,18 +1514,39 @@ func (mr *gRPCBidiReader) wait() {
1483
1514
1484
1515
// Close will notify stream manager goroutine that the reader has been closed, if it's still running.
1485
1516
func (mr * gRPCBidiReader ) close () error {
1486
- if mr .cancel != nil {
1487
- mr .cancel ()
1488
- }
1517
+ mr .closeManager <- true
1518
+ mr .closeReceiver <- true
1489
1519
mr .mu .Lock ()
1520
+ for key := range mr .mp {
1521
+ mr .mp [key ].callback (mr .mp [key ].offset , mr .mp [key ].totalBytesWritten , fmt .Errorf ("stream closed early" ))
1522
+ delete (mr .mp , key )
1523
+ }
1490
1524
mr .done = true
1491
1525
mr .activeTask = 0
1492
1526
mr .mu .Unlock ()
1493
- mr .closeReceiver <- true
1494
- mr .closeManager <- true
1527
+ mr .mu .Lock ()
1528
+ tryClosing := ! (mr .endReceiver && mr .endSender )
1529
+ mr .mu .Unlock ()
1530
+
1531
+ for tryClosing {
1532
+ mr .mu .Lock ()
1533
+ tryClosing = ! (mr .endReceiver && mr .endSender )
1534
+ mr .mu .Unlock ()
1535
+ }
1536
+ defer mr .cancel ()
1495
1537
return nil
1496
1538
}
1497
1539
1540
+ // drainInboundReadStream calls stream.Recv() repeatedly until an error is returned.
1541
+ // drainInboundReadStream always returns a non-nil error. io.EOF indicates all
1542
+ // messages were successfully read.
1543
+ func drainInboundReadStream (stream storagepb.Storage_BidiReadObjectClient ) (err error ) {
1544
+ for err == nil {
1545
+ _ , err = stream .Recv ()
1546
+ }
1547
+ return err
1548
+ }
1549
+
1498
1550
func (mrr * gRPCBidiReader ) getHandle () []byte {
1499
1551
return mrr .readHandle
1500
1552
}
@@ -1925,6 +1977,8 @@ type gRPCBidiReader struct {
1925
1977
objectSize int64 // always use the mutex when accessing this variable
1926
1978
retrier func (error , string )
1927
1979
streamRecreation bool // This helps us identify if stream recreation is in progress or not. If stream recreation gets called from two goroutine then this will stop second one.
1980
+ endReceiver bool
1981
+ endSender bool
1928
1982
}
1929
1983
1930
1984
// gRPCReader is used by storage.Reader if the experimental option WithGRPCBidiReads is passed.
@@ -2653,11 +2707,11 @@ func bucketContext(ctx context.Context, bucket string) context.Context {
2653
2707
return gax .InsertMetadataIntoOutgoingContext (ctx , hds ... )
2654
2708
}
2655
2709
2656
- // drainInboundStream calls stream.Recv() repeatedly until an error is returned.
2710
+ // drainInboundWriteStream calls stream.Recv() repeatedly until an error is returned.
2657
2711
// It returns the last Resource received on the stream, or nil if no Resource
2658
- // was returned. drainInboundStream always returns a non-nil error. io.EOF
2712
+ // was returned. drainInboundWriteStream always returns a non-nil error. io.EOF
2659
2713
// indicates all messages were successfully read.
2660
- func drainInboundStream (stream storagepb.Storage_BidiWriteObjectClient ) (object * storagepb.Object , err error ) {
2714
+ func drainInboundWriteStream (stream storagepb.Storage_BidiWriteObjectClient ) (object * storagepb.Object , err error ) {
2661
2715
for err == nil {
2662
2716
var resp * storagepb.BidiWriteObjectResponse
2663
2717
resp , err = stream .Recv ()
@@ -2737,7 +2791,7 @@ func (s *gRPCOneshotBidiWriteBufferSender) sendBuffer(ctx context.Context, buf [
2737
2791
2738
2792
sendErr := s .stream .Send (req )
2739
2793
if sendErr != nil {
2740
- obj , err = drainInboundStream (s .stream )
2794
+ obj , err = drainInboundWriteStream (s .stream )
2741
2795
s .stream = nil
2742
2796
if sendErr != io .EOF {
2743
2797
err = sendErr
@@ -2750,7 +2804,7 @@ func (s *gRPCOneshotBidiWriteBufferSender) sendBuffer(ctx context.Context, buf [
2750
2804
s .stream .CloseSend ()
2751
2805
// Oneshot uploads only read from the response stream on completion or
2752
2806
// failure
2753
- obj , err = drainInboundStream (s .stream )
2807
+ obj , err = drainInboundWriteStream (s .stream )
2754
2808
s .stream = nil
2755
2809
if err == io .EOF {
2756
2810
err = nil
@@ -2862,7 +2916,7 @@ func (s *gRPCResumableBidiWriteBufferSender) sendBuffer(ctx context.Context, buf
2862
2916
2863
2917
sendErr := s .stream .Send (req )
2864
2918
if sendErr != nil {
2865
- obj , err = drainInboundStream (s .stream )
2919
+ obj , err = drainInboundWriteStream (s .stream )
2866
2920
s .stream = nil
2867
2921
if err == io .EOF {
2868
2922
// This is unexpected - we got an error on Send(), but not on Recv().
@@ -2874,7 +2928,7 @@ func (s *gRPCResumableBidiWriteBufferSender) sendBuffer(ctx context.Context, buf
2874
2928
2875
2929
if finishWrite {
2876
2930
s .stream .CloseSend ()
2877
- obj , err = drainInboundStream (s .stream )
2931
+ obj , err = drainInboundWriteStream (s .stream )
2878
2932
s .stream = nil
2879
2933
if err == io .EOF {
2880
2934
err = nil
@@ -2971,6 +3025,5 @@ func checkCanceled(err error) error {
2971
3025
if status .Code (err ) == codes .Canceled {
2972
3026
return context .Canceled
2973
3027
}
2974
-
2975
3028
return err
2976
3029
}
0 commit comments