risingwave_common/global_jvm.rs
1// Copyright 2025 RisingWave Labs
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use std::ops::Deref;
16use std::sync::OnceLock;
17
18use anyhow::Context as _;
19use jni::JavaVM;
20
21/// Type alias for a function that builds a JVM.
22pub type JvmBuilder = fn() -> anyhow::Result<JavaVM>;
23
24/// Registered JVM builder from other crates. Should only be one.
25#[linkme::distributed_slice]
26pub static JVM_BUILDER: [JvmBuilder];
27
28/// Wrapper for the global JVM instance.
29///
30/// To obtain the instance, use [`Jvm::get_or_init()`] or [`Jvm::get()`].
31#[derive(Clone, Copy, Debug)]
32#[repr(transparent)]
33pub struct Jvm(pub &'static JavaVM);
34
35static INSTANCE: OnceLock<JavaVM> = OnceLock::new();
36
37impl Jvm {
38 /// Get the global singleton JVM instance, initializing it with the registered builder if not already initialized.
39 pub fn get_or_init() -> anyhow::Result<Self> {
40 INSTANCE
41 .get_or_try_init(|| {
42 let builder = JVM_BUILDER
43 .iter()
44 .next()
45 .context("no JVM builder is registered")?;
46 builder()
47 })
48 .map(Self)
49 }
50
51 /// Get the global singleton JVM instance, returning `None` if not initialized.
52 ///
53 /// Use [`Jvm::get_or_init()`] if you want to initialize the JVM.
54 pub fn get() -> Option<Self> {
55 INSTANCE.get().map(Self)
56 }
57}
58
59impl Deref for Jvm {
60 type Target = JavaVM;
61
62 fn deref(&self) -> &Self::Target {
63 self.0
64 }
65}