-
Notifications
You must be signed in to change notification settings - Fork 1.1k
spanner-jdbc: Step 15 - ConnectionOptions and SpannerPool #5890
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
spanner-jdbc: Step 15 - ConnectionOptions and SpannerPool #5890
Conversation
d0f3f18 to
4829312
Compare
|
|
||
| @Override | ||
| public boolean isClosed() { | ||
| // TODO Auto-generated method stub |
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.
please delete these
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.
done
51a3ceb to
a6d9f88
Compare
| Spanner createSpanner(SpannerPoolKey key) { | ||
| SpannerOptions.Builder builder = SpannerOptions.newBuilder(); | ||
| builder | ||
| .setClientLibToken(MoreObjects.firstNonNull(key.userAgent, JdbcDriver.getClientLibToken())) |
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.
Here is how spring-cloud-gcp does it: https://github.com/spring-cloud/spring-cloud-gcp/blob/master/spring-cloud-gcp-autoconfigure/src/main/java/org/springframework/cloud/gcp/autoconfigure/spanner/GcpSpannerAutoConfiguration.java#L126. I'd prefer this approach so we don't need to add the setter in the builder.
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's something that we would need to discuss with the Spanner team in that case. The header used by spring-cloud-gcp sets a 'User-Agent' header, the client lib token of the JDBC driver sets the ApiClientHeader ('x-goog-api-client'). My initial solution was also what spring-cloud-gcp did, but it didn't show up in the monitoring that the Spanner team had. The ApiClientHeader did, which is why this solution was chosen, and the monitoring is now built around that.
That being said, I looked a little bit more into the spring-cloud-gcp solution and compared that with the original solution for the JDBC driver, and I noticed one important difference: spring-cloud-gcp sets a 'User-Agent' header, the JDBC driver used a 'user-agent' header, so that could be the reason it didn't show up.
| if (!initialized) { | ||
| initialize(); | ||
| } | ||
| if (spanners.containsKey(key)) { |
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.
personal preference, but I'd make this a get and null check
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.
Agree, in this case that is more appropriate, as the return value of the getSpanner(...) method should never be null (even if the map somehow contained a null value for the key).
| registeredConnectionsForSpanner = new ArrayList<>(); | ||
| connections.put(key, registeredConnectionsForSpanner); | ||
| } | ||
| registeredConnectionsForSpanner.add(connection); |
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.
is it possible to have duplicate connections?
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'm not 100% sure what you mean with 'duplicate' connections in this case, but:
- Several
Connectioninstances can share the sameSpannerinstance, and aSpannerinstance should only be closed once all the relatedConnectioninstances have been closed. The reason behind this is thatSpannerinstances are heavy-weight objects that should live throughout (most of) the lifetime of an application. ASpannerinstance also maintains a session pool.Connectioninstances are relatively light-weight objects that an application may create and close many times during its lifetime. In Cloud Spanner terms, aConnectionis comparable to aSession. But as the JDBC driver is built on top of the client library, and the client library does not expose sessions and session management, this solution is the closest we can get havingConnection==Session. Connectioninstances are not thread safe and should not be used by several processes at the same time. An application will normally either maintain its own connection pool and reuse connections through this pool, or create and close connections when needed for a process.ConnectionImpldoes not override the defaultequals(Object)method, so different connection instances will never be considered equal.
...ntrib/google-cloud-spanner-jdbc/src/main/java/com/google/cloud/spanner/jdbc/SpannerPool.java
Show resolved
Hide resolved
...ntrib/google-cloud-spanner-jdbc/src/main/java/com/google/cloud/spanner/jdbc/SpannerPool.java
Show resolved
Hide resolved
| * should not have been used for a {@link Connection} before it is closed by this method. | ||
| */ | ||
| @VisibleForTesting | ||
| void closeUnusedSpanners(long closeSpannerAfterMillisecondsUnused) { |
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.
where does this parameter get its value?
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.
The default value that is used when nothing else is configured is found here:
Line 75 in a6d9f88
| private static final long DEFAULT_CLOSE_SPANNER_AFTER_MILLISECONDS_UNUSED = 60000L; |
This value is currently only configurable for testing. A client application cannot change this value and will always use the default.
get and check for null is more appropriate in this case, as we would never want to return null from this method
| initialize(); | ||
| } | ||
| if (spanners.containsKey(key)) { | ||
| if (spanners.get(key) == null) { |
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 think this is backwards now?
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.
can we add some more testing around this?
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.
Oops, that's indeed backward. It's already covered by the test case here, but because this PR has build errors, I didn't pick up on that one. I added the same error to the private repo and ran the test cases, and there were multiple test failures.
…#5890) * add ConnectionOptions * add SpannerPool * removed auto-generated methods * changed to get-and-check-for-null get and check for null is more appropriate in this case, as we would never want to return null from this method * added documentation * fixed wrong null check
A
ConnectionImplinstance, which is the internal Spanner connection API, can only be created from aConnectionOptionsinstance. All connections that are created byConnectionOptionsare registered with aSpannerPoolthat keeps track of the connections that have been opened and whichSpannerinstances from the client library are associated with which connection. TheSpannerinstances are kept in a pool and reused for connections because these are heavyweight objects that are expensive to create and maintain, and are intended to live as long as the application interacts with Cloud Spanner.This change also adds a client lib token property to
SpannerOptionsin the client library. This token will be used to track the usage of the JDBC driver. The actual usage of this token will be added in a separate PR.This PR contains a couple of stub classes that will be replaced by the actual classes in subsequent PRs. This is done to keep the PR as small as possible. The stubs are: