diff --git a/Cargo.lock b/Cargo.lock index 99627dd7e940..4aeee484c62d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5265,6 +5265,12 @@ version = "3.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8bb03732005da905c88227371639bf1ad885cc712789c011c31c5fb3ab3ccf02" +[[package]] +name = "inventory" +version = "0.3.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f958d3d68f4167080a18141e10381e7634563984a537f2a49a30fd8e53ac5767" + [[package]] name = "io-extras" version = "0.18.1" @@ -5712,26 +5718,6 @@ version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" -[[package]] -name = "linkme" -version = "0.3.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b53ad6a33de58864705954edb5ad5d571a010f9e296865ed43dc72a5621b430" -dependencies = [ - "linkme-impl", -] - -[[package]] -name = "linkme-impl" -version = "0.3.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04e542a18c94a9b6fcc7adb090fa3ba6b79ee220a16404f325672729f32a66ff" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.48", -] - [[package]] name = "linux-raw-sys" version = "0.1.4" @@ -9332,8 +9318,8 @@ dependencies = [ "expect-test", "futures-async-stream", "futures-util", + "inventory", "itertools 0.12.0", - "linkme", "madsim-tokio", "md5", "moka", @@ -9374,7 +9360,6 @@ dependencies = [ "icelake", "itertools 0.12.0", "jsonbb", - "linkme", "madsim-tokio", "md5", "num-traits", @@ -9435,8 +9420,8 @@ dependencies = [ "futures-async-stream", "iana-time-zone", "icelake", + "inventory", "itertools 0.12.0", - "linkme", "madsim-tokio", "madsim-tonic", "maplit", diff --git a/src/expr/core/Cargo.toml b/src/expr/core/Cargo.toml index 03ed84ac6a21..95cdfc6094ca 100644 --- a/src/expr/core/Cargo.toml +++ b/src/expr/core/Cargo.toml @@ -40,8 +40,8 @@ either = "1" enum-as-inner = "0.6" futures-async-stream = { workspace = true } futures-util = "0.3" +inventory = "0.3" itertools = "0.12" -linkme = { version = "0.3", features = ["used_linker"] } md5 = "0.7" moka = { version = "0.12", features = ["sync"] } num-traits = "0.2" diff --git a/src/expr/core/src/codegen.rs b/src/expr/core/src/codegen.rs index c9022e40aec9..56e2078c7aaf 100644 --- a/src/expr/core/src/codegen.rs +++ b/src/expr/core/src/codegen.rs @@ -15,5 +15,5 @@ pub use async_trait::async_trait; pub use futures_async_stream::try_stream; pub use futures_util::stream::BoxStream; +pub use inventory; pub use itertools::multizip; -pub use linkme; diff --git a/src/expr/core/src/sig/mod.rs b/src/expr/core/src/sig/mod.rs index 747779f81e99..84c2d07dd6c4 100644 --- a/src/expr/core/src/sig/mod.rs +++ b/src/expr/core/src/sig/mod.rs @@ -33,10 +33,10 @@ use crate::ExprError; /// The global registry of all function signatures. pub static FUNCTION_REGISTRY: LazyLock = LazyLock::new(|| { let mut map = FunctionRegistry::default(); - tracing::info!("found {} functions", FUNCTIONS.len()); - for f in FUNCTIONS { - map.insert(f()); + for f in inventory::iter:: { + map.insert((f.0)()); } + tracing::info!("found {} functions", map.len()); map }); @@ -144,6 +144,11 @@ impl FunctionRegistry { (sig.type_infer)(args) } + /// Returns the number of function signatures in the registry. + pub fn len(&self) -> usize { + self.0.len() + } + /// Returns an iterator of all function signatures. pub fn iter(&self) -> impl Iterator { self.0.values().flatten() @@ -186,6 +191,11 @@ pub struct FuncSign { pub deprecated: bool, } +/// A new type around a function that returns a [`FuncSign`]. Used for registering +/// function signatures from `#[function]` attributes in the entire codebase. +pub struct FuncSignBuilder(pub fn() -> FuncSign); +inventory::collect!(FuncSignBuilder); + impl fmt::Debug for FuncSign { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!( @@ -457,7 +467,3 @@ pub enum FuncBuilder { }, Udf, } - -/// A static distributed slice of functions defined by `#[function]`. -#[linkme::distributed_slice] -pub static FUNCTIONS: [fn() -> FuncSign]; diff --git a/src/expr/impl/Cargo.toml b/src/expr/impl/Cargo.toml index e7b765820dfd..05e8136c9361 100644 --- a/src/expr/impl/Cargo.toml +++ b/src/expr/impl/Cargo.toml @@ -33,7 +33,6 @@ hex = "0.4" icelake = { workspace = true } itertools = "0.12" jsonbb = "0.1.2" -linkme = { version = "0.3", features = ["used_linker"] } md5 = "0.7" num-traits = "0.2" openssl = { version = "0.10", features = ["vendored"] } diff --git a/src/expr/macro/src/gen.rs b/src/expr/macro/src/gen.rs index 1da6470cf38e..45dba1d15844 100644 --- a/src/expr/macro/src/gen.rs +++ b/src/expr/macro/src/gen.rs @@ -162,7 +162,6 @@ impl FunctionAttr { let deprecated = self.deprecated; Ok(quote! { - #[risingwave_expr::codegen::linkme::distributed_slice(risingwave_expr::sig::FUNCTIONS)] fn #ctor_name() -> risingwave_expr::sig::FuncSign { use risingwave_common::types::{DataType, DataTypeName}; use risingwave_expr::sig::{FuncSign, SigDataType, FuncBuilder}; @@ -177,6 +176,9 @@ impl FunctionAttr { deprecated: #deprecated, } } + risingwave_expr::codegen::inventory::submit! { + risingwave_expr::sig::FuncSignBuilder(#ctor_name) + } }) } @@ -652,7 +654,6 @@ impl FunctionAttr { let deprecated = self.deprecated; Ok(quote! { - #[risingwave_expr::codegen::linkme::distributed_slice(risingwave_expr::sig::FUNCTIONS)] fn #ctor_name() -> risingwave_expr::sig::FuncSign { use risingwave_common::types::{DataType, DataTypeName}; use risingwave_expr::sig::{FuncSign, SigDataType, FuncBuilder}; @@ -672,6 +673,9 @@ impl FunctionAttr { deprecated: #deprecated, } } + risingwave_expr::codegen::inventory::submit! { + risingwave_expr::sig::FuncSignBuilder(#ctor_name) + } }) } @@ -984,7 +988,6 @@ impl FunctionAttr { let deprecated = self.deprecated; Ok(quote! { - #[risingwave_expr::codegen::linkme::distributed_slice(risingwave_expr::sig::FUNCTIONS)] fn #ctor_name() -> risingwave_expr::sig::FuncSign { use risingwave_common::types::{DataType, DataTypeName}; use risingwave_expr::sig::{FuncSign, SigDataType, FuncBuilder}; @@ -999,6 +1002,9 @@ impl FunctionAttr { deprecated: #deprecated, } } + risingwave_expr::codegen::inventory::submit! { + risingwave_expr::sig::FuncSignBuilder(#ctor_name) + } }) } diff --git a/src/frontend/Cargo.toml b/src/frontend/Cargo.toml index 878afa6f2a7b..e21431720bd7 100644 --- a/src/frontend/Cargo.toml +++ b/src/frontend/Cargo.toml @@ -39,8 +39,8 @@ futures = { version = "0.3", default-features = false, features = ["alloc"] } futures-async-stream = { workspace = true } iana-time-zone = "0.1" icelake = { workspace = true } +inventory = "0.3" itertools = "0.12" -linkme = { version = "0.3", features = ["used_linker"] } maplit = "1" md5 = "0.7.0" memcomparable = "0.2" diff --git a/src/frontend/macro/src/lib.rs b/src/frontend/macro/src/lib.rs index 36b7f33eb99c..b1e4e5e77840 100644 --- a/src/frontend/macro/src/lib.rs +++ b/src/frontend/macro/src/lib.rs @@ -114,7 +114,6 @@ fn gen_sys_table(attr: Attr, item_fn: ItemFn) -> Result { let handle_error = return_result.then(|| quote!(?)); Ok(quote! { - #[linkme::distributed_slice(crate::catalog::system_catalog::SYS_CATALOGS_SLICE)] #[no_mangle] // to prevent duplicate schema.table name fn #gen_fn_name() -> crate::catalog::system_catalog::BuiltinCatalog { const _: () = { @@ -136,6 +135,9 @@ fn gen_sys_table(attr: Attr, item_fn: ItemFn) -> Result { }), }) } + ::inventory::submit! { + crate::catalog::system_catalog::BuiltinCatalogBuilder(#gen_fn_name) + } }) } @@ -155,7 +157,6 @@ fn gen_sys_view(attr: Attr, item_struct: ItemStruct) -> Result { }; Ok(quote! { - #[linkme::distributed_slice(crate::catalog::system_catalog::SYS_CATALOGS_SLICE)] #[no_mangle] // to prevent duplicate schema.table name fn #gen_fn_name() -> crate::catalog::system_catalog::BuiltinCatalog { let fields = #struct_type::fields(); @@ -166,5 +167,8 @@ fn gen_sys_view(attr: Attr, item_struct: ItemStruct) -> Result { columns: fields, }) } + ::inventory::submit! { + crate::catalog::system_catalog::BuiltinCatalogBuilder(#gen_fn_name) + } }) } diff --git a/src/frontend/src/catalog/system_catalog/mod.rs b/src/frontend/src/catalog/system_catalog/mod.rs index 3b73be3afbdd..5b32f54b8a15 100644 --- a/src/frontend/src/catalog/system_catalog/mod.rs +++ b/src/frontend/src/catalog/system_catalog/mod.rs @@ -325,21 +325,23 @@ pub fn get_sys_views_in_schema(schema_name: &str) -> Vec> { .collect() } +/// A new type around a function that returns a [`BuiltinCatalog`]. Used for registering +/// builtin catalogs from `#[system_catalog]` attributes in the `frontend` crate. +pub(crate) struct BuiltinCatalogBuilder(pub fn() -> BuiltinCatalog); +inventory::collect!(BuiltinCatalogBuilder); + /// The global registry of all builtin catalogs. pub static SYS_CATALOGS: LazyLock = LazyLock::new(|| { - tracing::info!("found {} catalogs", SYS_CATALOGS_SLICE.len()); - assert!(SYS_CATALOGS_SLICE.len() <= MAX_SYS_CATALOG_NUM as usize); - let catalogs = SYS_CATALOGS_SLICE - .iter() - .map(|f| f()) + let catalogs = inventory::iter:: + .into_iter() + .map(|b| (b.0)()) .sorted_by_key(|c| c.full_name()) - .collect(); + .collect_vec(); + assert!(catalogs.len() <= MAX_SYS_CATALOG_NUM as usize); + tracing::info!("found {} catalogs", catalogs.len()); SystemCatalog { catalogs } }); -#[linkme::distributed_slice] -pub static SYS_CATALOGS_SLICE: [fn() -> BuiltinCatalog]; - #[async_trait] impl SysCatalogReader for SysCatalogReaderImpl { async fn read_table(&self, table_id: &TableId) -> Result {