- 
                Notifications
    
You must be signed in to change notification settings  - Fork 3.8k
 
chore: consistent expressionEvaluator.eval result memory ownership #19438
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 2 commits
6e34f7c
              bd96719
              3823411
              825a00a
              acfd9c8
              143f864
              ad2d767
              9b74208
              File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | 
|---|---|---|
| 
          
            
          
           | 
    @@ -19,7 +19,9 @@ func TestNewFilterPipeline(t *testing.T) { | |
| } | ||
| 
     | 
||
| t.Run("filter with true literal predicate", func(t *testing.T) { | ||
| alloc := memory.DefaultAllocator | ||
| alloc := memory.NewCheckedAllocator(memory.NewGoAllocator()) | ||
                
       | 
||
| defer alloc.AssertSize(t, 0) | ||
| 
     | 
||
| schema := arrow.NewSchema(fields, nil) | ||
| 
     | 
||
| // Create input data using arrowtest.Rows | ||
| 
        
          
        
         | 
    @@ -41,7 +43,7 @@ func TestNewFilterPipeline(t *testing.T) { | |
| } | ||
| 
     | 
||
| // Create filter pipeline | ||
| pipeline := NewFilterPipeline(filter, input, expressionEvaluator{}) | ||
| pipeline := NewFilterPipeline(filter, input, expressionEvaluator{}, alloc) | ||
| defer pipeline.Close() | ||
| 
     | 
||
| // Read the pipeline output | ||
| 
        
          
        
         | 
    @@ -56,7 +58,9 @@ func TestNewFilterPipeline(t *testing.T) { | |
| }) | ||
| 
     | 
||
| t.Run("filter with false literal predicate", func(t *testing.T) { | ||
| alloc := memory.DefaultAllocator | ||
| alloc := memory.NewCheckedAllocator(memory.NewGoAllocator()) | ||
| defer alloc.AssertSize(t, 0) | ||
| 
     | 
||
| schema := arrow.NewSchema(fields, nil) | ||
| 
     | 
||
| // Create input data using arrowtest.Rows | ||
| 
        
          
        
         | 
    @@ -80,7 +84,7 @@ func TestNewFilterPipeline(t *testing.T) { | |
| } | ||
| 
     | 
||
| // Create filter pipeline | ||
| pipeline := NewFilterPipeline(filter, input, expressionEvaluator{}) | ||
| pipeline := NewFilterPipeline(filter, input, expressionEvaluator{}, alloc) | ||
| defer pipeline.Close() | ||
| 
     | 
||
| // Read the pipeline output | ||
| 
        
          
        
         | 
    @@ -92,7 +96,9 @@ func TestNewFilterPipeline(t *testing.T) { | |
| }) | ||
| 
     | 
||
| t.Run("filter on boolean column with column expression", func(t *testing.T) { | ||
| alloc := memory.DefaultAllocator | ||
| alloc := memory.NewCheckedAllocator(memory.NewGoAllocator()) | ||
| defer alloc.AssertSize(t, 0) | ||
| 
     | 
||
| schema := arrow.NewSchema(fields, nil) | ||
| 
     | 
||
| // Create input data using arrowtest.Rows | ||
| 
        
          
        
         | 
    @@ -117,7 +123,7 @@ func TestNewFilterPipeline(t *testing.T) { | |
| } | ||
| 
     | 
||
| // Create filter pipeline | ||
| pipeline := NewFilterPipeline(filter, input, expressionEvaluator{}) | ||
| pipeline := NewFilterPipeline(filter, input, expressionEvaluator{}, alloc) | ||
| defer pipeline.Close() | ||
| 
     | 
||
| // Create expected output (only rows where valid=true) | ||
| 
        
          
        
         | 
    @@ -138,7 +144,9 @@ func TestNewFilterPipeline(t *testing.T) { | |
| }) | ||
| 
     | 
||
| t.Run("filter on multiple columns with binary expressions", func(t *testing.T) { | ||
| alloc := memory.DefaultAllocator | ||
| alloc := memory.NewCheckedAllocator(memory.NewGoAllocator()) | ||
| defer alloc.AssertSize(t, 0) | ||
| 
     | 
||
| schema := arrow.NewSchema(fields, nil) | ||
| 
     | 
||
| // Create input data using arrowtest.Rows | ||
| 
          
            
          
           | 
    @@ -170,7 +178,7 @@ func TestNewFilterPipeline(t *testing.T) { | |
| } | ||
| 
     | 
||
| // Create filter pipeline | ||
| pipeline := NewFilterPipeline(filter, input, expressionEvaluator{}) | ||
| pipeline := NewFilterPipeline(filter, input, expressionEvaluator{}, alloc) | ||
| defer pipeline.Close() | ||
| 
     | 
||
| // Create expected output (only rows where name=="Bob" AND valid!=false) | ||
| 
        
          
        
         | 
    @@ -191,7 +199,9 @@ func TestNewFilterPipeline(t *testing.T) { | |
| 
     | 
||
| // TODO: instead of returning empty batch, filter should read the next non-empty batch. | ||
| t.Run("filter on empty batch", func(t *testing.T) { | ||
| alloc := memory.DefaultAllocator | ||
| alloc := memory.NewCheckedAllocator(memory.NewGoAllocator()) | ||
| defer alloc.AssertSize(t, 0) | ||
| 
     | 
||
| schema := arrow.NewSchema(fields, nil) | ||
| 
     | 
||
| // Create empty input data using arrowtest.Rows | ||
| 
        
          
        
         | 
    @@ -210,7 +220,7 @@ func TestNewFilterPipeline(t *testing.T) { | |
| } | ||
| 
     | 
||
| // Create filter pipeline | ||
| pipeline := NewFilterPipeline(filter, input, expressionEvaluator{}) | ||
| pipeline := NewFilterPipeline(filter, input, expressionEvaluator{}, alloc) | ||
| defer pipeline.Close() | ||
| 
     | 
||
| record, err := pipeline.Read(t.Context()) | ||
| 
        
          
        
         | 
    @@ -223,7 +233,9 @@ func TestNewFilterPipeline(t *testing.T) { | |
| }) | ||
| 
     | 
||
| t.Run("filter with multiple input batches", func(t *testing.T) { | ||
| alloc := memory.DefaultAllocator | ||
| alloc := memory.NewCheckedAllocator(memory.NewGoAllocator()) | ||
| defer alloc.AssertSize(t, 0) | ||
| 
     | 
||
| schema := arrow.NewSchema(fields, nil) | ||
| 
     | 
||
| // Create input data split across multiple batches using arrowtest.Rows | ||
| 
          
            
          
           | 
    @@ -251,7 +263,7 @@ func TestNewFilterPipeline(t *testing.T) { | |
| } | ||
| 
     | 
||
| // Create filter pipeline | ||
| pipeline := NewFilterPipeline(filter, input, expressionEvaluator{}) | ||
| pipeline := NewFilterPipeline(filter, input, expressionEvaluator{}, alloc) | ||
| defer pipeline.Close() | ||
| 
     | 
||
| // Create expected output (only rows where valid=true) | ||
| 
          
            
          
           | 
    @@ -284,7 +296,9 @@ func TestNewFilterPipeline(t *testing.T) { | |
| }) | ||
| 
     | 
||
| t.Run("filter with null values", func(t *testing.T) { | ||
| alloc := memory.DefaultAllocator | ||
| alloc := memory.NewCheckedAllocator(memory.NewGoAllocator()) | ||
| defer alloc.AssertSize(t, 0) | ||
| 
     | 
||
| schema := arrow.NewSchema(fields, nil) | ||
| 
     | 
||
| // Create input data with null values | ||
| 
        
          
        
         | 
    @@ -309,7 +323,7 @@ func TestNewFilterPipeline(t *testing.T) { | |
| } | ||
| 
     | 
||
| // Create filter pipeline | ||
| pipeline := NewFilterPipeline(filter, input, expressionEvaluator{}) | ||
| pipeline := NewFilterPipeline(filter, input, expressionEvaluator{}, alloc) | ||
| defer pipeline.Close() | ||
| 
     | 
||
| // Create expected output (only rows where valid=true, including null name) | ||
| 
          
            
          
           | 
    ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I prefer the
defer Releaseapproach when it's in an open/close situation, so for example immediately after creating an array. So, how would you feel about either a) moving this up into the builders loop above, soor b) storing the new record in a variable and then releasing synchronously (ie. not in a defer)?
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That was an existing pattern that I followed. I am not a fan of doing that without
deferbecause there is risk of missing important cleanup in case of early returns or failures. Usingdeferis as simple and reliable asfinallyin Java.