wombatu-kun opened a new pull request, #16733:
URL: https://github.com/apache/iceberg/pull/16733

   Follow-up to #16731, which removed the same redundant `java.time` 
allocations from the ORC timestamp *readers* (generic and Flink). This PR does 
the writer side for Flink.
   
   `FlinkOrcWriters` defines four ORC timestamp writer classes - 
`TimestampWriter`, `TimestampTzWriter`, `TimestampNanoWriter` and 
`TimestampNanoTzWriter` - each of which converted a `TimestampData` to a 
`java.time` object per value to derive the ORC column-vector fields. The 
no-zone writers (`TimestampWriter`, `TimestampNanoWriter`) used 
`data.toInstant().atOffset(ZoneOffset.UTC)`, which allocates, per value, a 
transient `Instant`, an `OffsetDateTime`, and a `ZoneRules` (plus a small 
backing array) - because `instant.atOffset(ZoneOffset.UTC)` routes through 
`OffsetDateTime.ofInstant(instant, zone)`, which calls `zone.getRules()`, and 
`ZoneOffset.getRules()` returns a freshly allocated `ZoneRules` on every call.
   
   `TimestampData` already exposes the values ORC needs without any allocation: 
`getMillisecond()` (epoch millis) and `getNanoOfMillisecond()`. This rewrites 
all four writers to read those directly and fill the `TimestampColumnVector` 
with plain arithmetic. ORC's `TimestampColumnVector` stores `time` as epoch 
millis and `nanos` as nanoseconds-within-the-second, so:
   
       long millis = data.getMillisecond();
       cv.time[rowId] = millis;
       int nanosOfSecond = (int) Math.floorMod(millis, 1_000L) * 1_000_000 + 
data.getNanoOfMillisecond();
       cv.nanos[rowId] = nanosOfSecond / 1_000 * 1_000;   // micros writers; 
the nano writers keep nanosOfSecond
   
   This is behavior-preserving. The old code computed `cv.time` as 
`instant.toEpochMilli()`, which equals `data.getMillisecond()`, and `cv.nanos` 
from the instant's nanos-of-second, which equals `Math.floorMod(millis, 1000) * 
1_000_000 + data.getNanoOfMillisecond()`; `Math.floorMod` yields the correct 
non-negative milli-of-second for pre-1970 (negative) timestamps. The now-unused 
`java.time` imports and two stale 
`@SuppressWarnings("JavaInstantGetSecondsGetNano")` are removed. The change is 
applied identically across the three Flink version trees (v1.20, v2.0, v2.1) - 
that is, all four writer classes in each of the three copies of 
`FlinkOrcWriters` (3 files total).
   
   Benchmark (JMH, JDK 17, `SingleShotTime`, `gc` profiler; allocation is 
`gc.alloc.rate.norm`, which is deterministic), driving the value writers over a 
reused `TimestampColumnVector`, 10.24M writes/op:
   
   | Writer | time (before -> after) | allocation (before -> after) |
   | --- | --- | --- |
   | timestamp (no zone) | 0.376 -> 0.026 s/op | 144 -> ~0 B/value |
   | timestamptz | 0.073 -> 0.030 s/op | already ~0 B/value |
   
   The no-zone writers carried the real allocation (the `ZoneRules` from 
`atOffset`); the tz writers were already allocation-free (the JIT 
scalar-replaces their `Instant`) but still gain from dropping the 
`Instant`/`toEpochMilli` work. The generic data-module ORC writers were checked 
too, but they use `toInstant().toEpochMilli()` without `atOffset`, which the 
JIT already scalar-replaces even on the end-to-end write path (no measurable 
allocation), so they are intentionally left unchanged.
   
   Testing: covered by the existing `TestFlinkOrcReaderWriter` round-trip test 
(writes then reads back, including pre-1970 timestamps and multiple timezones); 
passes for all three Flink versions.
   


-- 
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