Commit 269357f
authored
fix(go): fix potential deadlocks in reader (#60)
## What's Changed
## Fix Critical Deadlocks and Race Conditions in Snowflake Record Reader
This PR addresses multiple critical concurrency issues in the Snowflake
driver's `recordReader` that could cause complete application hangs
under normal racing conditions.
### Issues Fixed
*1. Critical Deadlock: `Release()` Blocking Forever*
*Problem*: When `Release()` was called while producer goroutines were
blocked on channel sends, a permanent deadlock occurred:
* `Release()` cancels context and attempts to drain channels
* Producer goroutines blocked on `ch <- rec` cannot see the cancellation
* Channels never close because producers never exit
* `Release()` blocks forever on `for rec := range ch`
*Fix:* Added a `done` channel that signals when all producer goroutines
have completed. `Release()` now waits for this signal before attempting
to drain channels.
*2. Severe Deadlock: Non-Context-Aware Channel Sends*
*Problem:* Channel send operations at lines 694 and 732 checked context
before the send but not during:
```go
for rr.Next() && ctx.Err() == nil { // Context checked here
// ...
ch <- rec // But send blocks here without checking context
}
```
*Fix:* Wrapped all channel sends in `select` statements with context
awareness:
```go
select {
case chs[0] <- rec:
// Successfully sent
case <-ctx.Done():
rec.Release()
return ctx.Err()
}
```
*3. Critical Race Condition: Nil Channel Reads*
*Problem:* Channels were created asynchronously in goroutines after
`newRecordReader` returned. If `Next()` was called quickly after
creation, it could read from uninitialized (nil) channels, causing
infinite blocking.
*Fix:* Initialize all channels upfront before starting any goroutines:
```go
chs := make([]chan arrow.RecordBatch, len(batches))
for i := range chs {
chs[i] = make(chan arrow.RecordBatch, bufferSize)
}
```
*4. Goroutine Leaks on Initialization Errors*
*Problem:* Error paths only cleaned up the first channel, potentially
leaking goroutines if initialization failed after starting concurrent
operations.
*Fix:* Moved all error-prone initialization (GetStream, NewReader)
before goroutine creation, and added proper cleanup on errors.
----------------------
#### Changes
* Added `done` channel to `reader` struct to signal goroutine completion
* Initialize all channels upfront to eliminate race conditions
* Use context-aware sends with `select` statements for all channel
operations
* Update `Release()` to wait on `done` channel before draining
* Reorganize initialization to handle errors before starting goroutines
* Signal completion by closing `done` channel after all producers finish
#### Reproduction Scenarios Prevented
*Deadlock:*
1. bufferSize = 1, producer generates 2 records quickly
2. Channel becomes full after first record
3. Producer blocks on send
4. Consumer calls Release() before Next()
5. Without fix: permanent deadlock
6. With fix: producer responds to cancellation, Release() completes
*Race Condition:*
1. Query returns 3 batches
2. First batch processes quickly
3. Next() advances to second channel
4. Without fix: reads from nil channel, blocks forever
5. With fix: channel already initialized, works correctly
Backport of apache/arrow-adbc#3870.1 parent ea369d9 commit 269357f
1 file changed
+66
-26
lines changed| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
548 | 548 | | |
549 | 549 | | |
550 | 550 | | |
| 551 | + | |
551 | 552 | | |
552 | 553 | | |
553 | 554 | | |
| |||
655 | 656 | | |
656 | 657 | | |
657 | 658 | | |
658 | | - | |
659 | | - | |
660 | | - | |
661 | | - | |
662 | | - | |
663 | | - | |
664 | | - | |
665 | | - | |
666 | | - | |
667 | | - | |
668 | | - | |
669 | | - | |
670 | | - | |
671 | | - | |
672 | | - | |
673 | | - | |
674 | | - | |
675 | | - | |
676 | | - | |
677 | | - | |
| 659 | + | |
678 | 660 | | |
679 | 661 | | |
680 | 662 | | |
681 | 663 | | |
682 | 664 | | |
| 665 | + | |
| 666 | + | |
| 667 | + | |
| 668 | + | |
| 669 | + | |
| 670 | + | |
| 671 | + | |
| 672 | + | |
| 673 | + | |
683 | 674 | | |
684 | 675 | | |
685 | 676 | | |
686 | 677 | | |
| 678 | + | |
687 | 679 | | |
688 | 680 | | |
689 | 681 | | |
690 | 682 | | |
691 | 683 | | |
692 | 684 | | |
693 | 685 | | |
| 686 | + | |
694 | 687 | | |
695 | 688 | | |
696 | 689 | | |
697 | 690 | | |
698 | 691 | | |
699 | 692 | | |
| 693 | + | |
| 694 | + | |
| 695 | + | |
| 696 | + | |
| 697 | + | |
| 698 | + | |
| 699 | + | |
| 700 | + | |
| 701 | + | |
| 702 | + | |
| 703 | + | |
| 704 | + | |
| 705 | + | |
| 706 | + | |
| 707 | + | |
| 708 | + | |
| 709 | + | |
| 710 | + | |
| 711 | + | |
700 | 712 | | |
701 | 713 | | |
702 | 714 | | |
| |||
706 | 718 | | |
707 | 719 | | |
708 | 720 | | |
709 | | - | |
| 721 | + | |
710 | 722 | | |
711 | 723 | | |
712 | 724 | | |
| |||
715 | 727 | | |
716 | 728 | | |
717 | 729 | | |
718 | | - | |
| 730 | + | |
| 731 | + | |
| 732 | + | |
| 733 | + | |
| 734 | + | |
| 735 | + | |
| 736 | + | |
| 737 | + | |
| 738 | + | |
| 739 | + | |
719 | 740 | | |
720 | 741 | | |
721 | 742 | | |
722 | 743 | | |
723 | | - | |
724 | | - | |
725 | 744 | | |
726 | 745 | | |
727 | 746 | | |
728 | 747 | | |
729 | | - | |
| 748 | + | |
730 | 749 | | |
731 | 750 | | |
732 | 751 | | |
| |||
753 | 772 | | |
754 | 773 | | |
755 | 774 | | |
756 | | - | |
| 775 | + | |
| 776 | + | |
| 777 | + | |
| 778 | + | |
| 779 | + | |
| 780 | + | |
| 781 | + | |
| 782 | + | |
| 783 | + | |
| 784 | + | |
757 | 785 | | |
758 | 786 | | |
759 | 787 | | |
| |||
768 | 796 | | |
769 | 797 | | |
770 | 798 | | |
| 799 | + | |
| 800 | + | |
771 | 801 | | |
772 | 802 | | |
773 | 803 | | |
| |||
819 | 849 | | |
820 | 850 | | |
821 | 851 | | |
| 852 | + | |
| 853 | + | |
| 854 | + | |
| 855 | + | |
| 856 | + | |
| 857 | + | |
| 858 | + | |
822 | 859 | | |
| 860 | + | |
| 861 | + | |
| 862 | + | |
823 | 863 | | |
824 | 864 | | |
825 | 865 | | |
| |||
0 commit comments