rraulinio opened a new issue, #1265:
URL: https://github.com/apache/iceberg-go/issues/1265

   ### Apache Iceberg version
   
   main (development)
   
   ### Please describe the bug 🐞
   
   # Description
   
   Running the table package under the race detector exposed two independent 
races.
   
   ## 1. `PartitionToPath` races on lazy partition field name escaping
   
   `PartitionSpec.PartitionToPath()` can be called concurrently by fanout 
writers. It builds partition paths like:
   
   ```text
   bucket=1/day=2026-06-23
   ```
   
   To avoid escaping the partition field name every time, 
`PartitionField.EscapedName()` cached the escaped field name lazily on the 
`PartitionField` itself.
   
   That lazy cache write is not safe when multiple goroutines use the same 
`PartitionSpec` at the same time. The first concurrent calls can all see an 
empty `escapedName` and then write to the same field concurrently.
   
   Observed stack:
   
   ```text
   WARNING: DATA RACE
   Write at ... by goroutine ...:
     github.com/apache/iceberg-go.(*PartitionField).EscapedName()
         partitions.go:74
     github.com/apache/iceberg-go.(*PartitionSpec).PartitionToPath()
         partitions.go:541
     
github.com/apache/iceberg-go/table.(*partitionedFanoutWriter).partitionPath()
         table/partitioned_fanout_writer.go:73
     
github.com/apache/iceberg-go/table.(*partitionedFanoutWriter).processRecord()
         table/partitioned_fanout_writer.go:159
   ```
   
   ## 2. Parallel table tests mutate the shared positional delete schema
   
   Some table tests pass the package-level `iceberg.PositionalDeleteSchema` 
directly into `MetadataBuilder.AddSchema`.
   
   `AddSchema` assigns a schema ID onto the schema object it receives. That 
means the test is not just reading the shared `PositionalDeleteSchema`; it can 
mutate it.
   
   This is fine in serial execution, but several table tests run with 
`t.Parallel()`. Under the race detector, two tests can touch the same shared 
schema pointer at the same time:
   
   - one test writes `schema.ID` through `MetadataBuilder.AddSchema`
   - another test reads the same schema while adding/building metadata
   
   # How to reproduce
   
   The table package was not included in the existing CI race-detector target, 
so run it manually:
   
   ```bash
   go test -race ./table/...
   ```
   
   # Expected behavior
   
   The table package should pass under the race detector.
   
   `PartitionSpec.PartitionToPath()` should be safe to call concurrently 
because fanout writers naturally call it from multiple goroutines.
   
   Tests should not mutate package-level shared schemas from parallel subtests.
   
   # Proposed fixes
   
   1. Precompute `PartitionField.escapedName` during 
`PartitionSpec.initialize()`, which is already called by partition spec 
constructors and JSON unmarshal. Then make `EscapedName()` read-only at call 
time: return the precomputed value when present, otherwise compute 
`url.QueryEscape(p.Name)` without writing back.
   
   2. Clone `iceberg.PositionalDeleteSchema` before passing it to 
`MetadataBuilder.AddSchema` in the affected tests. This keeps the fix 
test-local and avoids changing production `MetadataBuilder` behavior.
   
   3. Add `./table/...` to the CI race-detector command so these paths stay 
covered.
   
   # Verification
   
   After the fixes:
   
   ```text
   go test -race ./table/...
   ok   github.com/apache/iceberg-go/table      27.394s
   ok   github.com/apache/iceberg-go/table/compaction   48.721s
   ok   github.com/apache/iceberg-go/table/dv   (cached)
   ok   github.com/apache/iceberg-go/table/internal     (cached)
   ok   github.com/apache/iceberg-go/table/substrait    (cached)
   ```


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to