Skip to content
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

CASSJAVA-53 Upgrade Guava to 33.3.1-jre #1998

Merged
merged 1 commit into from
Jan 7, 2025

Conversation

lukasz-antoniak
Copy link
Member

Fixes CASSJAVA-53.

@@ -78,6 +74,8 @@
<includes>
<include>org.apache.cassandra:java-driver-guava-shaded</include>
<include>com.google.guava:guava</include>
<include>com.google.guava:failureaccess</include>
Copy link
Member Author

Choose a reason for hiding this comment

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

New dependency introduced in Guava 27.0.

@@ -78,6 +74,8 @@
<includes>
<include>org.apache.cassandra:java-driver-guava-shaded</include>
<include>com.google.guava:guava</include>
<include>com.google.guava:failureaccess</include>
<include>com.google.j2objc:j2objc-annotations</include>
Copy link
Member Author

Choose a reason for hiding this comment

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

Required because SettableFuture extends AbstractFuture where the @ReflectionSupport(value = ReflectionSupport.Level.FULL) annotation is present.

Copy link
Contributor

Choose a reason for hiding this comment

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

That's... lame, but yeah, it appears to be the case.

<groupId>org.codehaus.mojo</groupId>
<artifactId>animal-sniffer-annotations</artifactId>
<groupId>com.google.guava</groupId>
<artifactId>listenablefuture</artifactId>
Copy link
Member Author

Choose a reason for hiding this comment

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

ListenableFuture is already part of Guava in 27.0 and this is an optional dependency.

Copy link
Contributor

Choose a reason for hiding this comment

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

Is this strictly necessary? We're specifying excludes here, and per the blog post the listenablefuture dependency used for Guava is some weird high-numbered version (to avoid conflicts) which does indeed appear to be the case. If I'm understanding this correctly (and I'm not at all sure I am) we should be able to include the listenablefuture dependency at no real cost.

The only benefit that I can see for this approach is that it simplifies this POM a bit to not have a weird exclusion based on a weird Guava design choice.

Thoughts?

Copy link
Member Author

Choose a reason for hiding this comment

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

Based on this Guava issue, I guess that sequence of actions was the following:

  1. Old Guava version contained ListenableFuture interface.
  2. At some point Guava team decided to split parts of Guava into other libraries.
  3. Later, it was decided to move the ListenableFuture interface back to Guava.
  4. To prevent issues with dependency resolution, on some build systems, com.google.guava:listenablefuture was assigned a high version number and empty JAR, so that the com.google.guava:listenablefuture:1.0 is not picked up (which included colliding ListenableFuture interface definition).

I wanted to exclude it, because was thinking that driver users will not need to download extra JAR. However, since it is our shaded Guava version, it has no impact to driver users. I am OK removing this exclusion.

Copy link
Contributor

Choose a reason for hiding this comment

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

The blog post I referenced earlier provides a more complete picture of what happened @lukasz-antoniak:

Some Android library developers have told us that they would like to use ListenableFuture in their APIs, but they know that a full Guava dependency would be bad for apps that don't use Proguard. To address this, we are planning to release a separate artifact that contains only ListenableFuture.

I'm not quite sure I understand all of this; seems to me like you'd either want ListenableFuture by itself or Guava (with ListenableFuture still there)... which in turn means there's no real reason for Guava to depend on the listenablefuture lib. That change clearly was introduced to avoid seeing duplicate class definition errors... but I'm not sure how that's accomplished.

Regardless, I agree that removing the dependency should be harmless. For extra confirmation I confirmed that the high-numbered listenablefuture lib does indeed have no classes:

$ jar tf /work/maven/repo/com/google/guava/listenablefuture/9999.0-empty-to-avoid-conflict-with-guava/listenablefuture-9999.0-empty-to-avoid-conflict-with-guava.jar
META-INF/MANIFEST.MF
META-INF/
META-INF/maven/
META-INF/maven/com.google.guava/
META-INF/maven/com.google.guava/listenablefuture/
META-INF/maven/com.google.guava/listenablefuture/pom.xml
META-INF/maven/com.google.guava/listenablefuture/pom.properties

I've got a final DS Jenkins run going with the most recent changes. Assuming there's no regression there (and I strongly suspect there won't be one) we're good to go on this one.

Copy link
Contributor

Choose a reason for hiding this comment

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

DS Jenkins run finished with a few test failures but they all look spurious. Should probably investigate these at some point in the future but I'm gonna hold off for now... if we start to see them more regularly I'll become more concerned.

</exclusion>
<exclusion>
<groupId>org.codehaus.mojo</groupId>
<artifactId>animal-sniffer-annotations</artifactId>
Copy link
Member Author

Choose a reason for hiding this comment

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

Dependency animal-sniffer-annotations have removed from Guava 28.2.

@@ -17,7 +17,7 @@
*/
package com.datastax.dse.driver.internal.core.cql.reactive;

import static org.assertj.core.api.Fail.fail;
import static org.junit.Assert.fail;
Copy link
Contributor

Choose a reason for hiding this comment

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

This change seems unrelated.

Copy link
Member Author

Choose a reason for hiding this comment

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

Fixed.

@@ -81,7 +81,10 @@ public List<T> getElements() {
}

public void awaitTermination() {
Uninterruptibles.awaitUninterruptibly(latch, 1, TimeUnit.MINUTES);
boolean interrupted = Uninterruptibles.awaitUninterruptibly(latch, 1, TimeUnit.MINUTES);
Copy link
Contributor

Choose a reason for hiding this comment

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

I believe this is incorrect. The returned value is the result of latch.await(), not a flag indicating that the thread was interrupted. The javadocs of CountDownLatch.wait() say:

return true if the count reached zero and false if the waiting time elapsed before the count reached zero.

Also looking at the implementation of awaitUninterruptibly in 33.3, there is already a finally block where the thread is being interrupted:

    } finally {
      if (interrupted) {
        Thread.currentThread().interrupt();
      }
    }

So I believe this code should be changed to:

if (!Uninterruptibles.awaitUninterruptibly(latch, 1, TimeUnit.MINUTES)) {
  fail("subscriber not terminated");
}

Copy link
Member Author

Choose a reason for hiding this comment

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

You are absolutely right. Not sure why I decided to change the code like this.

@absurdfarce
Copy link
Contributor

I've kicked off a DS Jenkins build for this PR; will report results back when it's done.

if (latch.getCount() > 0) fail("subscriber not terminated");
if (!Uninterruptibles.awaitUninterruptibly(latch, 1, TimeUnit.MINUTES)) {
fail("subscriber not terminated");
}
Copy link
Contributor

Choose a reason for hiding this comment

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

This seems correct. Uninterruptibles.awaitUninterruptibly() calls CountDownLatch.await() which (as I read the Javadoc) returns true if the latch count is equal to zero: in all other cases (including throwing an InterruptedException) execution continues until the timeout is hit which results in a return value of false.

@absurdfarce
Copy link
Contributor

DS Jenkins test run was fine: one test failure but it looks to be completely unrelated (and caused by some ccm failure). So we're good to go on that front.

@absurdfarce
Copy link
Contributor

@lukasz-antoniak Can you squash the commits on this PR into a single commit for me? Once that's done I think this guy is ready to merge.

patch by Lukasz Antoniak; reviewed by Alexandre Dutra and Bret McGuire for CASSJAVA-53
@lukasz-antoniak
Copy link
Member Author

Thank you, squashed and commit message updated.

@absurdfarce absurdfarce merged commit 8c10099 into apache:4.x Jan 7, 2025
1 check failed
@absurdfarce absurdfarce changed the title Upgrade Guava to 33.3.1-jre CASSJAVA-53 Upgrade Guava to 33.3.1-jre Jan 16, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants