Skip to content

Conversation

@dgd-contributor
Copy link

@dgd-contributor dgd-contributor commented Jun 9, 2021

Why are the changes needed?

With Long.minValue cast to an instant, secs will be floored in function microsToInstant and cause overflow when multiply with Micros_per_second

def microsToInstant(micros: Long): Instant = {
  val secs = Math.floorDiv(micros, MICROS_PER_SECOND)
  // Unfolded Math.floorMod(us, MICROS_PER_SECOND) to reuse the result of
  // the above calculation of `secs` via `floorDiv`.
  val mos = micros - secs * MICROS_PER_SECOND  <- it will overflow here
  Instant.ofEpochSecond(secs, mos * NANOS_PER_MICROS)
}

But the overflow is acceptable because it won't produce any change to the result

However, when convert the instant back to micro value, it will raise Overflow Error

def instantToMicros(instant: Instant): Long = {
  val us = Math.multiplyExact(instant.getEpochSecond, MICROS_PER_SECOND) <- It overflow here
  val result = Math.addExact(us, NANOSECONDS.toMicros(instant.getNano))
  result
}

Code to reproduce this error

instantToMicros(microToInstant(Long.MinValue))

Does this PR introduce any user-facing change?

No

How was this patch tested?

Test added

@dgd-contributor dgd-contributor changed the title [SPARK-35679][SQL] instantToMicros overflow [SPARK-35679][SQL][WIP] instantToMicros overflow Jun 9, 2021
@AmplabJenkins
Copy link

Can one of the admins verify this patch?

@dgd-contributor dgd-contributor force-pushed the SPARK-35679_instantToMicro branch from 8977b16 to 249d299 Compare June 9, 2021 08:30
@gengliangwang
Copy link
Member

As I mentioned in #32814 (comment)

We can fix it but it is too corner. The fix makes performance worse, too.

I will leave this one to other committers. cc @MaxGekk @cloud-fan

Co-authored-by: Gengliang Wang <[email protected]>
@dgd-contributor
Copy link
Author

As I mentioned in #32814 (comment)

We can fix it but it is too corner. The fix makes performance worse, too.

I will leave this one to other committers. cc @MaxGekk @cloud-fan

Thanks

Copy link
Contributor

@cloud-fan cloud-fan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. I don't think perf is a big concern in this code path. And the overhead seems very small.

@cloud-fan cloud-fan changed the title [SPARK-35679][SQL][WIP] instantToMicros overflow [SPARK-35679][SQL] instantToMicros overflow Jun 9, 2021
@github-actions github-actions bot added the SQL label Jun 9, 2021
@MaxGekk
Copy link
Member

MaxGekk commented Jun 9, 2021

@gengliangwang Thank for the ping. I will review this today.

@MaxGekk
Copy link
Member

MaxGekk commented Jun 9, 2021

@dgd-contributor Regarding PR's description. Could you fix indentations in code examples according to the code style.

@dgd-contributor dgd-contributor requested a review from MaxGekk June 10, 2021 04:38
@MaxGekk
Copy link
Member

MaxGekk commented Jun 10, 2021

@dgd-contributor Does the issue exist in other versions: 3.0, 3.1?

@MaxGekk
Copy link
Member

MaxGekk commented Jun 10, 2021

+1, LGTM. Merging to master, 3.1 and 3.0.
Thank you @dgd-contributor , and @cloud-fan for your review.

@MaxGekk MaxGekk closed this in aa3de40 Jun 10, 2021
MaxGekk pushed a commit that referenced this pull request Jun 10, 2021
### Why are the changes needed?
With Long.minValue cast to an instant, secs will be floored in function microsToInstant and cause overflow when multiply with Micros_per_second

```
def microsToInstant(micros: Long): Instant = {
  val secs = Math.floorDiv(micros, MICROS_PER_SECOND)
  // Unfolded Math.floorMod(us, MICROS_PER_SECOND) to reuse the result of
  // the above calculation of `secs` via `floorDiv`.
  val mos = micros - secs * MICROS_PER_SECOND  <- it will overflow here
  Instant.ofEpochSecond(secs, mos * NANOS_PER_MICROS)
}
```

But the overflow is acceptable because it won't produce any change to the result

However, when convert the instant back to micro value, it will raise Overflow Error

```
def instantToMicros(instant: Instant): Long = {
  val us = Math.multiplyExact(instant.getEpochSecond, MICROS_PER_SECOND) <- It overflow here
  val result = Math.addExact(us, NANOSECONDS.toMicros(instant.getNano))
  result
}
```

Code to reproduce this error
```
instantToMicros(microToInstant(Long.MinValue))
```

### Does this PR introduce _any_ user-facing change?
No

### How was this patch tested?
Test added

Closes #32839 from dgd-contributor/SPARK-35679_instantToMicro.

Authored-by: dgd-contributor <[email protected]>
Signed-off-by: Max Gekk <[email protected]>
(cherry picked from commit aa3de40)
Signed-off-by: Max Gekk <[email protected]>
MaxGekk pushed a commit that referenced this pull request Jun 10, 2021
With Long.minValue cast to an instant, secs will be floored in function microsToInstant and cause overflow when multiply with Micros_per_second

```
def microsToInstant(micros: Long): Instant = {
  val secs = Math.floorDiv(micros, MICROS_PER_SECOND)
  // Unfolded Math.floorMod(us, MICROS_PER_SECOND) to reuse the result of
  // the above calculation of `secs` via `floorDiv`.
  val mos = micros - secs * MICROS_PER_SECOND  <- it will overflow here
  Instant.ofEpochSecond(secs, mos * NANOS_PER_MICROS)
}
```

But the overflow is acceptable because it won't produce any change to the result

However, when convert the instant back to micro value, it will raise Overflow Error

```
def instantToMicros(instant: Instant): Long = {
  val us = Math.multiplyExact(instant.getEpochSecond, MICROS_PER_SECOND) <- It overflow here
  val result = Math.addExact(us, NANOSECONDS.toMicros(instant.getNano))
  result
}
```

Code to reproduce this error
```
instantToMicros(microToInstant(Long.MinValue))
```

No

Test added

Closes #32839 from dgd-contributor/SPARK-35679_instantToMicro.

Authored-by: dgd-contributor <[email protected]>
Signed-off-by: Max Gekk <[email protected]>
(cherry picked from commit aa3de40)
Signed-off-by: Max Gekk <[email protected]>
@dgd-contributor
Copy link
Author

Thanks @MaxGekk @cloud-fan @gengliangwang for supporting

flyrain pushed a commit to flyrain/spark that referenced this pull request Sep 21, 2021
### Why are the changes needed?
With Long.minValue cast to an instant, secs will be floored in function microsToInstant and cause overflow when multiply with Micros_per_second

```
def microsToInstant(micros: Long): Instant = {
  val secs = Math.floorDiv(micros, MICROS_PER_SECOND)
  // Unfolded Math.floorMod(us, MICROS_PER_SECOND) to reuse the result of
  // the above calculation of `secs` via `floorDiv`.
  val mos = micros - secs * MICROS_PER_SECOND  <- it will overflow here
  Instant.ofEpochSecond(secs, mos * NANOS_PER_MICROS)
}
```

But the overflow is acceptable because it won't produce any change to the result

However, when convert the instant back to micro value, it will raise Overflow Error

```
def instantToMicros(instant: Instant): Long = {
  val us = Math.multiplyExact(instant.getEpochSecond, MICROS_PER_SECOND) <- It overflow here
  val result = Math.addExact(us, NANOSECONDS.toMicros(instant.getNano))
  result
}
```

Code to reproduce this error
```
instantToMicros(microToInstant(Long.MinValue))
```

### Does this PR introduce _any_ user-facing change?
No

### How was this patch tested?
Test added

Closes apache#32839 from dgd-contributor/SPARK-35679_instantToMicro.

Authored-by: dgd-contributor <[email protected]>
Signed-off-by: Max Gekk <[email protected]>
(cherry picked from commit aa3de40)
Signed-off-by: Max Gekk <[email protected]>
fishcus pushed a commit to fishcus/spark that referenced this pull request Jan 12, 2022
### Why are the changes needed?
With Long.minValue cast to an instant, secs will be floored in function microsToInstant and cause overflow when multiply with Micros_per_second

```
def microsToInstant(micros: Long): Instant = {
  val secs = Math.floorDiv(micros, MICROS_PER_SECOND)
  // Unfolded Math.floorMod(us, MICROS_PER_SECOND) to reuse the result of
  // the above calculation of `secs` via `floorDiv`.
  val mos = micros - secs * MICROS_PER_SECOND  <- it will overflow here
  Instant.ofEpochSecond(secs, mos * NANOS_PER_MICROS)
}
```

But the overflow is acceptable because it won't produce any change to the result

However, when convert the instant back to micro value, it will raise Overflow Error

```
def instantToMicros(instant: Instant): Long = {
  val us = Math.multiplyExact(instant.getEpochSecond, MICROS_PER_SECOND) <- It overflow here
  val result = Math.addExact(us, NANOSECONDS.toMicros(instant.getNano))
  result
}
```

Code to reproduce this error
```
instantToMicros(microToInstant(Long.MinValue))
```

### Does this PR introduce _any_ user-facing change?
No

### How was this patch tested?
Test added

Closes apache#32839 from dgd-contributor/SPARK-35679_instantToMicro.

Authored-by: dgd-contributor <[email protected]>
Signed-off-by: Max Gekk <[email protected]>
(cherry picked from commit aa3de40)
Signed-off-by: Max Gekk <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants