-
Notifications
You must be signed in to change notification settings - Fork 124
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
chore: add support for virtual threads to Connection API (#2789)
Adds support for using virtual threads in the Connection API. Virtual threads can be enabled for two things: 1. As the StatementExecutor thread for each connection. 2. As the gRPC transport thread pool. Both options can (for now) only be set in the Connection API. Setting any of these options only has any effect if the application is running on Java 21 or higher.
- Loading branch information
Showing
15 changed files
with
444 additions
and
43 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
99 changes: 99 additions & 0 deletions
99
google-cloud-spanner/src/main/java/com/google/cloud/spanner/ThreadFactoryUtil.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,99 @@ | ||
/* | ||
* Copyright 2024 Google LLC | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
package com.google.cloud.spanner; | ||
|
||
import com.google.api.core.InternalApi; | ||
import com.google.common.util.concurrent.ThreadFactoryBuilder; | ||
import java.lang.reflect.InvocationTargetException; | ||
import java.lang.reflect.Method; | ||
import java.util.concurrent.ExecutorService; | ||
import java.util.concurrent.Executors; | ||
import java.util.concurrent.ThreadFactory; | ||
import javax.annotation.Nullable; | ||
|
||
/** Utility class for creating a thread factory for daemon or virtual threads. */ | ||
@InternalApi | ||
public class ThreadFactoryUtil { | ||
|
||
/** | ||
* Tries to create a thread factory for virtual threads, and otherwise falls back to creating a | ||
* platform thread factory that creates daemon threads. Virtual threads are supported from JDK21. | ||
* | ||
* @param baseNameFormat the base name format for the threads, '-%d' will be appended to the | ||
* actual thread name format | ||
* @param tryVirtualThreads whether to try to use virtual threads if available or not | ||
* @return a {@link ThreadFactory} that produces virtual threads (Java 21 or higher) or platform | ||
* daemon threads | ||
*/ | ||
@InternalApi | ||
public static ThreadFactory createVirtualOrPlatformDaemonThreadFactory( | ||
String baseNameFormat, boolean tryVirtualThreads) { | ||
ThreadFactory virtualThreadFactory = | ||
tryVirtualThreads ? tryCreateVirtualThreadFactory(baseNameFormat) : null; | ||
if (virtualThreadFactory != null) { | ||
return virtualThreadFactory; | ||
} | ||
|
||
return new ThreadFactoryBuilder().setDaemon(true).setNameFormat(baseNameFormat + "-%d").build(); | ||
} | ||
|
||
/** | ||
* Tries to create a {@link ThreadFactory} that creates virtual threads. Returns null if virtual | ||
* threads are not supported on this JVM. | ||
*/ | ||
@InternalApi | ||
@Nullable | ||
public static ThreadFactory tryCreateVirtualThreadFactory(String baseNameFormat) { | ||
try { | ||
Class<?> threadBuilderClass = Class.forName("java.lang.Thread$Builder"); | ||
Method ofVirtualMethod = Thread.class.getDeclaredMethod("ofVirtual"); | ||
Object virtualBuilder = ofVirtualMethod.invoke(null); | ||
Method nameMethod = threadBuilderClass.getDeclaredMethod("name", String.class, long.class); | ||
virtualBuilder = nameMethod.invoke(virtualBuilder, baseNameFormat + "-", 0); | ||
Method factoryMethod = threadBuilderClass.getDeclaredMethod("factory"); | ||
return (ThreadFactory) factoryMethod.invoke(virtualBuilder); | ||
} catch (ClassNotFoundException | NoSuchMethodException ignore) { | ||
return null; | ||
} catch (InvocationTargetException | IllegalAccessException e) { | ||
throw new RuntimeException(e); | ||
} | ||
} | ||
|
||
/** | ||
* Tries to create an {@link ExecutorService} that creates a new virtual thread for each task that | ||
* it runs. Creating a new virtual thread is the recommended way to create executors using virtual | ||
* threads, instead of creating a pool of virtual threads. Returns null if virtual threads are not | ||
* supported on this JVM. | ||
*/ | ||
@InternalApi | ||
@Nullable | ||
public static ExecutorService tryCreateVirtualThreadPerTaskExecutor(String baseNameFormat) { | ||
ThreadFactory factory = tryCreateVirtualThreadFactory(baseNameFormat); | ||
if (factory != null) { | ||
try { | ||
Method newThreadPerTaskExecutorMethod = | ||
Executors.class.getDeclaredMethod("newThreadPerTaskExecutor", ThreadFactory.class); | ||
return (ExecutorService) newThreadPerTaskExecutorMethod.invoke(null, factory); | ||
} catch (NoSuchMethodException ignore) { | ||
return null; | ||
} catch (InvocationTargetException | IllegalAccessException e) { | ||
throw new RuntimeException(e); | ||
} | ||
} | ||
return null; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
48 changes: 48 additions & 0 deletions
48
...d-spanner/src/main/java/com/google/cloud/spanner/connection/ConnectionSpannerOptions.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
/* | ||
* Copyright 2024 Google LLC | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
package com.google.cloud.spanner.connection; | ||
|
||
import com.google.cloud.spanner.SpannerOptions; | ||
|
||
/** | ||
* This class is used for building {@link SpannerOptions} for {@link Connection} instances. It gives | ||
* access to (experimental) properties that are not public in the standard {@link SpannerOptions} | ||
* implementation. | ||
*/ | ||
class ConnectionSpannerOptions extends SpannerOptions { | ||
public static Builder newBuilder() { | ||
return new Builder(); | ||
} | ||
|
||
static class Builder extends SpannerOptions.Builder { | ||
Builder() {} | ||
|
||
@Override | ||
protected SpannerOptions.Builder setUseVirtualThreads(boolean useVirtualThreads) { | ||
return super.setUseVirtualThreads(useVirtualThreads); | ||
} | ||
|
||
@Override | ||
public ConnectionSpannerOptions build() { | ||
return new ConnectionSpannerOptions(this); | ||
} | ||
} | ||
|
||
ConnectionSpannerOptions(Builder builder) { | ||
super(builder); | ||
} | ||
} |
Oops, something went wrong.