Repository: apache/datafusion (language: rust)

Issue:
Replace `OnceLock` with `LazyLock`
### Is your feature request related to a problem or challenge?

LazyLock is stabilized in 1.80 🚀 
It is more ergonomic than OnceLock, it would be nice to switch to LazyLock

### Describe the solution you'd like

_No response_

### Describe alternatives you've considered

_No response_

### Additional context

_No response_


Discussion / hints:
I'm happy to take this one. For the uses of `OnceLock` in statics that currently have an associated getter function, such as `ROW_GROUP_METADATA` and `row_group_metadata` in `access_plan.rs`, would it be better to replace calls to the function with direct access to the static, or just simplify the implementation of the getter function without changing the call sites?
We can direct access to the static data, since it is not a breaking change, changing call sites is fine
take
We can't do that (yet). DataFusion MSRV is 1.76
> We can't do that (yet). DataFusion MSRV is 1.76

Oh, I forgot that. Sorry @Rafferty97 
MSRV is now 1.78 so we can probably revive this issue
@Rafferty97  I unassigned you but if you are still interested in working on this issue, please feel free to reassign it to yourself.

For anyone else who finds this issue, you can see what is needed in this PR: https://github.com/apache/datafusion/pull/11690 but that has bitrotted.

I would suggest just applying the same changes in a new PR
take
Didn't LazyLock become stable in 1.80.0 ? https://blog.rust-lang.org/2024/07/25/Rust-1.80.0.html

I just tried to use it in main and it wouldn't compile...
@jonahgao  has picked this ne up again: https://github.com/apache/datafusion/pull/13641
take
@comphead there are a few more of OnceLock references. I have another PR incoming and that should finally be sufficient to close this issue.
Thanks @AmosAidoo  ❤ 

Fix patch:
diff --git a/datafusion/expr/src/udaf.rs b/datafusion/expr/src/udaf.rs
index ae7196c9b10f..b4bbbf30f915 100644
--- a/datafusion/expr/src/udaf.rs
+++ b/datafusion/expr/src/udaf.rs
@@ -338,7 +338,7 @@ where
 /// # Basic Example
 /// ```
 /// # use std::any::Any;
-/// # use std::sync::OnceLock;
+/// # use std::sync::LazyLock;
 /// # use arrow::datatypes::DataType;
 /// # use datafusion_common::{DataFusionError, plan_err, Result};
 /// # use datafusion_expr::{col, ColumnarValue, Signature, Volatility, Expr, Documentation};
@@ -360,14 +360,14 @@ where
 ///   }
 /// }
 ///
-/// static DOCUMENTATION: OnceLock<Documentation> = OnceLock::new();
-///
-/// fn get_doc() -> &'static Documentation {
-///     DOCUMENTATION.get_or_init(|| {
+/// static DOCUMENTATION: LazyLock<Documentation> = LazyLock::new(|| {
 ///         Documentation::builder(DOC_SECTION_AGGREGATE, "calculates a geometric mean", "geo_mean(2.0)")
 ///             .with_argument("arg1", "The Float64 number for the geometric mean")
 ///             .build()
-///     })
+///     });
+///
+/// fn get_doc() -> &'static Documentation {
+///     &DOCUMENTATION
 /// }
 ///    
 /// /// Implement the AggregateUDFImpl trait for GeoMeanUdf
diff --git a/datafusion/expr/src/udf.rs b/datafusion/expr/src/udf.rs
index 74c3c2775c1c..8215b671a379 100644
--- a/datafusion/expr/src/udf.rs
+++ b/datafusion/expr/src/udf.rs
@@ -433,7 +433,7 @@ impl ReturnInfo {
 /// # Basic Example
 /// ```
 /// # use std::any::Any;
-/// # use std::sync::OnceLock;
+/// # use std::sync::LazyLock;
 /// # use arrow::datatypes::DataType;
 /// # use datafusion_common::{DataFusionError, plan_err, Result};
 /// # use datafusion_expr::{col, ColumnarValue, Documentation, ScalarFunctionArgs, Signature, Volatility};
@@ -453,14 +453,14 @@ impl ReturnInfo {
 ///   }
 /// }
 ///
-/// static DOCUMENTATION: OnceLock<Documentation> = OnceLock::new();
-///
-/// fn get_doc() -> &'static Documentation {
-///     DOCUMENTATION.get_or_init(|| {
+/// static DOCUMENTATION: LazyLock<Documentation> = LazyLock::new(|| {
 ///         Documentation::builder(DOC_SECTION_MATH, "Add one to an int32", "add_one(2)")
 ///             .with_argument("arg1", "The int32 number to add one to")
 ///             .build()
-///     })
+///     });
+///
+/// fn get_doc() -> &'static Documentation {
+///     &DOCUMENTATION
 /// }
 ///
 /// /// Implement the ScalarUDFImpl trait for AddOne
diff --git a/datafusion/expr/src/udwf.rs b/datafusion/expr/src/udwf.rs
index 96929ffeb0ed..4da63d7955f5 100644
--- a/datafusion/expr/src/udwf.rs
+++ b/datafusion/expr/src/udwf.rs
@@ -235,7 +235,7 @@ where
 /// # Basic Example
 /// ```
 /// # use std::any::Any;
-/// # use std::sync::OnceLock;
+/// # use std::sync::LazyLock;
 /// # use arrow::datatypes::{DataType, Field};
 /// # use datafusion_common::{DataFusionError, plan_err, Result};
 /// # use datafusion_expr::{col, Signature, Volatility, PartitionEvaluator, WindowFrame, ExprFunctionExt, Documentation};
@@ -257,14 +257,14 @@ where
 ///   }
 /// }
 ///
-/// static DOCUMENTATION: OnceLock<Documentation> = OnceLock::new();
+/// static DOCUMENTATION: LazyLock<Documentation> = LazyLock::new(|| {
+///     Documentation::builder(DOC_SECTION_ANALYTICAL, "smooths the windows", "smooth_it(2)")
+///         .with_argument("arg1", "The int32 number to smooth by")
+///         .build()
+/// });
 ///
 /// fn get_doc() -> &'static Documentation {
-///     DOCUMENTATION.get_or_init(|| {
-///         Documentation::builder(DOC_SECTION_ANALYTICAL, "smooths the windows", "smooth_it(2)")
-///             .with_argument("arg1", "The int32 number to smooth by")
-///             .build()
-///     })
+///     &DOCUMENTATION
 /// }
 ///
 /// /// Implement the WindowUDFImpl trait for SmoothIt
diff --git a/datafusion/functions-aggregate/src/bit_and_or_xor.rs b/datafusion/functions-aggregate/src/bit_and_or_xor.rs
index 6319a9c07dd2..50ab50abc9e2 100644
--- a/datafusion/functions-aggregate/src/bit_and_or_xor.rs
+++ b/datafusion/functions-aggregate/src/bit_and_or_xor.rs
@@ -42,7 +42,7 @@ use datafusion_expr::{
 use datafusion_expr::aggregate_doc_sections::DOC_SECTION_GENERAL;
 use datafusion_functions_aggregate_common::aggregate::groups_accumulator::prim_op::PrimitiveGroupsAccumulator;
 use std::ops::{BitAndAssign, BitOrAssign, BitXorAssign};
-use std::sync::OnceLock;
+use std::sync::LazyLock;
 
 /// This macro helps create group accumulators based on bitwise operations typically used internally
 /// and might not be necessary for users to call directly.
@@ -134,46 +134,46 @@ macro_rules! make_bitwise_udaf_expr_and_func {
     };
 }
 
-static BIT_AND_DOC: OnceLock<Documentation> = OnceLock::new();
+static BIT_AND_DOC: LazyLock<Documentation> = LazyLock::new(|| {
+    Documentation::builder(
+        DOC_SECTION_GENERAL,
+        "Computes the bitwise AND of all non-null input values.",
+        "bit_and(expression)",
+    )
+    .with_standard_argument("expression", Some("Integer"))
+    .build()
+});
 
 fn get_bit_and_doc() -> &'static Documentation {
-    BIT_AND_DOC.get_or_init(|| {
-        Documentation::builder(
-            DOC_SECTION_GENERAL,
-            "Computes the bitwise AND of all non-null input values.",
-            "bit_and(expression)",
-        )
-        .with_standard_argument("expression", Some("Integer"))
-        .build()
-    })
+    &BIT_AND_DOC
 }
 
-static BIT_OR_DOC: OnceLock<Documentation> = OnceLock::new();
+static BIT_OR_DOC: LazyLock<Documentation> = LazyLock::new(|| {
+    Documentation::builder(
+        DOC_SECTION_GENERAL,
+        "Computes the bitwise OR of all non-null input values.",
+        "bit_or(expression)",
+    )
+    .with_standard_argument("expression", Some("Integer"))
+    .build()
+});
 
 fn get_bit_or_doc() -> &'static Documentation {
-    BIT_OR_DOC.get_or_init(|| {
-        Documentation::builder(
-            DOC_SECTION_GENERAL,
-            "Computes the bitwise OR of all non-null input values.",
-            "bit_or(expression)",
-        )
-        .with_standard_argument("expression", Some("Integer"))
-        .build()
-    })
+    &BIT_OR_DOC
 }
 
-static BIT_XOR_DOC: OnceLock<Documentation> = OnceLock::new();
+static BIT_XOR_DOC: LazyLock<Documentation> = LazyLock::new(|| {
+    Documentation::builder(
+        DOC_SECTION_GENERAL,
+        "Computes the bitwise exclusive OR of all non-null input values.",
+        "bit_xor(expression)",
+    )
+    .with_standard_argument("expression", Some("Integer"))
+    .build()
+});
 
 fn get_bit_xor_doc() -> &'static Documentation {
-    BIT_XOR_DOC.get_or_init(|| {
-        Documentation::builder(
-            DOC_SECTION_GENERAL,
-            "Computes the bitwise exclusive OR of all non-null input values.",
-            "bit_xor(expression)",
-        )
-        .with_standard_argument("expression", Some("Integer"))
-        .build()
-    })
+    &BIT_XOR_DOC
 }
 
 make_bitwise_udaf_expr_and_func!(
diff --git a/datafusion/functions-aggregate/src/regr.rs b/datafusion/functions-aggregate/src/regr.rs
index f302b72f94b5..82575d15e50b 100644
--- a/datafusion/functions-aggregate/src/regr.rs
+++ b/datafusion/functions-aggregate/src/regr.rs
@@ -38,7 +38,7 @@ use datafusion_expr::{
 use std::any::Any;
 use std::fmt::Debug;
 use std::mem::size_of_val;
-use std::sync::OnceLock;
+use std::sync::LazyLock;
 
 macro_rules! make_regr_udaf_expr_and_func {
     ($EXPR_FN:ident, $AGGREGATE_UDF_FN:ident, $REGR_TYPE:expr) => {
@@ -132,11 +132,9 @@ impl RegrType {
     }
 }
 
-static DOCUMENTATION: OnceLock<HashMap<RegrType, Documentation>> = OnceLock::new();
-fn get_regr_docs() -> &'static HashMap<RegrType, Documentation> {
-    DOCUMENTATION.get_or_init(|| {
-        let mut hash_map = HashMap::new();
-        hash_map.insert(
+static DOCUMENTATION: LazyLock<HashMap<RegrType, Documentation>> = LazyLock::new(|| {
+    let mut hash_map = HashMap::new();
+    hash_map.insert(
             RegrType::Slope,
             Documentation::builder(
                 DOC_SECTION_STATISTICAL,
@@ -149,7 +147,7 @@ fn get_regr_docs() -> &'static HashMap<RegrType, Documentation> {
                 .build()
         );
 
-        hash_map.insert(
+    hash_map.insert(
             RegrType::Intercept,
             Documentation::builder(
                 DOC_SECTION_STATISTICAL,
@@ -162,19 +160,19 @@ fn get_regr_docs() -> &'static HashMap<RegrType, Documentation> {
                 .build()
         );
 
-        hash_map.insert(
-            RegrType::Count,
-            Documentation::builder(
-                DOC_SECTION_STATISTICAL,
-                    "Counts the number of non-null paired data points.",
-
-                "regr_count(expression_y, expression_x)")
-                .with_standard_argument("expression_y", Some("Dependent variable"))
-                .with_standard_argument("expression_x", Some("Independent variable"))
-                .build()
-        );
-
-        hash_map.insert(
+    hash_map.insert(
+        RegrType::Count,
+        Documentation::builder(
+            DOC_SECTION_STATISTICAL,
+            "Counts the number of non-null paired data points.",
+            "regr_count(expression_y, expression_x)",
+        )
+        .with_standard_argument("expression_y", Some("Dependent variable"))
+        .with_standard_argument("expression_x", Some("Independent variable"))
+        .build(),
+    );
+
+    hash_map.insert(
             RegrType::R2,
             Documentation::builder(
                 DOC_SECTION_STATISTICAL,
@@ -186,7 +184,7 @@ fn get_regr_docs() -> &'static HashMap<RegrType, Documentation> {
                 .build()
         );
 
-        hash_map.insert(
+    hash_map.insert(
             RegrType::AvgX,
             Documentation::builder(
                 DOC_SECTION_STATISTICAL,
@@ -198,7 +196,7 @@ fn get_regr_docs() -> &'static HashMap<RegrType, Documentation> {
                 .build()
         );
 
-        hash_map.insert(
+    hash_map.insert(
             RegrType::AvgY,
             Documentation::builder(
                 DOC_SECTION_STATISTICAL,
@@ -210,43 +208,45 @@ fn get_regr_docs() -> &'static HashMap<RegrType, Documentation> {
                 .build()
         );
 
-        hash_map.insert(
-            RegrType::SXX,
-            Documentation::builder(
-                DOC_SECTION_STATISTICAL,
-                    "Computes the sum of squares of the independent variable.",
-
-                "regr_sxx(expression_y, expression_x)")
-                .with_standard_argument("expression_y", Some("Dependent variable"))
-                .with_standard_argument("expression_x", Some("Independent variable"))
-                .build()
-        );
-
-        hash_map.insert(
-            RegrType::SYY,
-            Documentation::builder(
-                DOC_SECTION_STATISTICAL,
-                    "Computes the sum of squares of the dependent variable.",
-
-                "regr_syy(expression_y, expression_x)")
-                .with_standard_argument("expression_y", Some("Dependent variable"))
-                .with_standard_argument("expression_x", Some("Independent variable"))
-                .build()
-        );
-
-        hash_map.insert(
-            RegrType::SXY,
-            Documentation::builder(
-                DOC_SECTION_STATISTICAL,
-                    "Computes the sum of products of paired data points.",
-
-                "regr_sxy(expression_y, expression_x)")
-                .with_standard_argument("expression_y", Some("Dependent variable"))
-                .with_standard_argument("expression_x", Some("Independent variable"))
-                .build()
-        );
-        hash_map
-    })
+    hash_map.insert(
+        RegrType::SXX,
+        Documentation::builder(
+            DOC_SECTION_STATISTICAL,
+            "Computes the sum of squares of the independent variable.",
+            "regr_sxx(expression_y, expression_x)",
+        )
+        .with_standard_argument("expression_y", Some("Dependent variable"))
+        .with_standard_argument("expression_x", Some("Independent variable"))
+        .build(),
+    );
+
+    hash_map.insert(
+        RegrType::SYY,
+        Documentation::builder(
+            DOC_SECTION_STATISTICAL,
+            "Computes the sum of squares of the dependent variable.",
+            "regr_syy(expression_y, expression_x)",
+        )
+        .with_standard_argument("expression_y", Some("Dependent variable"))
+        .with_standard_argument("expression_x", Some("Independent variable"))
+        .build(),
+    );
+
+    hash_map.insert(
+        RegrType::SXY,
+        Documentation::builder(
+            DOC_SECTION_STATISTICAL,
+            "Computes the sum of products of paired data points.",
+            "regr_sxy(expression_y, expression_x)",
+        )
+        .with_standard_argument("expression_y", Some("Dependent variable"))
+        .with_standard_argument("expression_x", Some("Independent variable"))
+        .build(),
+    );
+    hash_map
+});
+fn get_regr_docs() -> &'static HashMap<RegrType, Documentation> {
+    &DOCUMENTATION
 }
 
 impl AggregateUDFImpl for Regr {
diff --git a/datafusion/functions-window/src/lead_lag.rs b/datafusion/functions-window/src/lead_lag.rs
index d73a5d86bbe6..5df20cf5b980 100644
--- a/datafusion/functions-window/src/lead_lag.rs
+++ b/datafusion/functions-window/src/lead_lag.rs
@@ -35,7 +35,7 @@ use std::any::Any;
 use std::cmp::min;
 use std::collections::VecDeque;
 use std::ops::{Neg, Range};
-use std::sync::{Arc, OnceLock};
+use std::sync::{Arc, LazyLock};
 
 get_or_init_udwf!(
     Lag,
@@ -148,38 +148,38 @@ impl WindowShift {
     }
 }
 
-static LAG_DOCUMENTATION: OnceLock<Documentation> = OnceLock::new();
+static LAG_DOCUMENTATION: LazyLock<Documentation> = LazyLock::new(|| {
+    Documentation::builder(DOC_SECTION_ANALYTICAL, "Returns value evaluated at the row that is offset rows before the \
+            current row within the partition; if there is no such row, instead return default \
+            (which must be of the same type as value).", "lag(expression, offset, default)")
+        .with_argument("expression", "Expression to operate on")
+        .with_argument("offset", "Integer. Specifies how many rows back \
+        the value of expression should be retrieved. Defaults to 1.")
+        .with_argument("default", "The default value if the offset is \
+        not within the partition. Must be of the same type as expression.")
+        .build()
+});
 
 fn get_lag_doc() -> &'static Documentation {
-    LAG_DOCUMENTATION.get_or_init(|| {
-        Documentation::builder(DOC_SECTION_ANALYTICAL, "Returns value evaluated at the row that is offset rows before the \
-                current row within the partition; if there is no such row, instead return default \
-                (which must be of the same type as value).", "lag(expression, offset, default)")
-            .with_argument("expression", "Expression to operate on")
-            .with_argument("offset", "Integer. Specifies how many rows back \
-            the value of expression should be retrieved. Defaults to 1.")
-            .with_argument("default", "The default value if the offset is \
-            not within the partition. Must be of the same type as expression.")
-            .build()
-    })
+    &LAG_DOCUMENTATION
 }
 
-static LEAD_DOCUMENTATION: OnceLock<Documentation> = OnceLock::new();
+static LEAD_DOCUMENTATION: LazyLock<Documentation> = LazyLock::new(|| {
+    Documentation::builder(DOC_SECTION_ANALYTICAL,
+            "Returns value evaluated at the row that is offset rows after the \
+            current row within the partition; if there is no such row, instead return default \
+            (which must be of the same type as value).",
+        "lead(expression, offset, default)")
+        .with_argument("expression", "Expression to operate on")
+        .with_argument("offset", "Integer. Specifies how many rows \
+        forward the value of expression should be retrieved. Defaults to 1.")
+        .with_argument("default", "The default value if the offset is \
+        not within the partition. Must be of the same type as expression.")
+        .build()
+});
 
 fn get_lead_doc() -> &'static Documentation {
-    LEAD_DOCUMENTATION.get_or_init(|| {
-        Documentation::builder(DOC_SECTION_ANALYTICAL,
-                "Returns value evaluated at the row that is offset rows after the \
-                current row within the partition; if there is no such row, instead return default \
-                (which must be of the same type as value).",
-            "lead(expression, offset, default)")
-            .with_argument("expression", "Expression to operate on")
-            .with_argument("offset", "Integer. Specifies how many rows \
-            forward the value of expression should be retrieved. Defaults to 1.")
-            .with_argument("default", "The default value if the offset is \
-            not within the partition. Must be of the same type as expression.")
-            .build()
-    })
+    &LEAD_DOCUMENTATION
 }
 
 impl WindowUDFImpl for WindowShift {
diff --git a/datafusion/functions-window/src/nth_value.rs b/datafusion/functions-window/src/nth_value.rs
index 16caa5293ed1..1c781bd8e5f3 100644
--- a/datafusion/functions-window/src/nth_value.rs
+++ b/datafusion/functions-window/src/nth_value.rs
@@ -23,7 +23,7 @@ use std::any::Any;
 use std::cmp::Ordering;
 use std::fmt::Debug;
 use std::ops::Range;
-use std::sync::OnceLock;
+use std::sync::LazyLock;
 
 use datafusion_common::arrow::array::ArrayRef;
 use datafusion_common::arrow::datatypes::{DataType, Field};
@@ -127,54 +127,54 @@ impl NthValue {
     }
 }
 
-static FIRST_VALUE_DOCUMENTATION: OnceLock<Documentation> = OnceLock::new();
+static FIRST_VALUE_DOCUMENTATION: LazyLock<Documentation> = LazyLock::new(|| {
+    Documentation::builder(
+        DOC_SECTION_ANALYTICAL,
+        "Returns value evaluated at the row that is the first row of the window \
+            frame.",
+        "first_value(expression)",
+    )
+    .with_argument("expression", "Expression to operate on")
+    .build()
+});
 
 fn get_first_value_doc() -> &'static Documentation {
-    FIRST_VALUE_DOCUMENTATION.get_or_init(|| {
-        Documentation::builder(
-            DOC_SECTION_ANALYTICAL,
-            "Returns value evaluated at the row that is the first row of the window \
-                frame.",
-            "first_value(expression)",
-        )
-        .with_argument("expression", "Expression to operate on")
-        .build()
-    })
+    &FIRST_VALUE_DOCUMENTATION
 }
 
-static LAST_VALUE_DOCUMENTATION: OnceLock<Documentation> = OnceLock::new();
+static LAST_VALUE_DOCUMENTATION: LazyLock<Documentation> = LazyLock::new(|| {
+    Documentation::builder(
+        DOC_SECTION_ANALYTICAL,
+        "Returns value evaluated at the row that is the last row of the window \
+            frame.",
+        "last_value(expression)",
+    )
+    .with_argument("expression", "Expression to operate on")
+    .build()
+});
 
 fn get_last_value_doc() -> &'static Documentation {
-    LAST_VALUE_DOCUMENTATION.get_or_init(|| {
-        Documentation::builder(
-            DOC_SECTION_ANALYTICAL,
-            "Returns value evaluated at the row that is the last row of the window \
-                frame.",
-            "last_value(expression)",
-        )
-        .with_argument("expression", "Expression to operate on")
-        .build()
-    })
+    &LAST_VALUE_DOCUMENTATION
 }
 
-static NTH_VALUE_DOCUMENTATION: OnceLock<Documentation> = OnceLock::new();
+static NTH_VALUE_DOCUMENTATION: LazyLock<Documentation> = LazyLock::new(|| {
+    Documentation::builder(
+        DOC_SECTION_ANALYTICAL,
+        "Returns value evaluated at the row that is the nth row of the window \
+            frame (counting from 1); null if no such row.",
+        "nth_value(expression, n)",
+    )
+    .with_argument(
+        "expression",
+        "The name the column of which nth \
+        value to retrieve",
+    )
+    .with_argument("n", "Integer. Specifies the n in nth")
+    .build()
+});
 
 fn get_nth_value_doc() -> &'static Documentation {
-    NTH_VALUE_DOCUMENTATION.get_or_init(|| {
-        Documentation::builder(
-            DOC_SECTION_ANALYTICAL,
-            "Returns value evaluated at the row that is the nth row of the window \
-                frame (counting from 1); null if no such row.",
-            "nth_value(expression, n)",
-        )
-        .with_argument(
-            "expression",
-            "The name the column of which nth \
-            value to retrieve",
-        )
-        .with_argument("n", "Integer. Specifies the n in nth")
-        .build()
-    })
+    &NTH_VALUE_DOCUMENTATION
 }
 
 impl WindowUDFImpl for NthValue {
diff --git a/datafusion/functions-window/src/rank.rs b/datafusion/functions-window/src/rank.rs
index dacee90bfad6..bd2edc5722eb 100644
--- a/datafusion/functions-window/src/rank.rs
+++ b/datafusion/functions-window/src/rank.rs
@@ -22,7 +22,7 @@ use std::any::Any;
 use std::fmt::Debug;
 use std::iter;
 use std::ops::Range;
-use std::sync::{Arc, OnceLock};
+use std::sync::{Arc, LazyLock};
 
 use crate::define_udwf_and_expr;
 use datafusion_common::arrow::array::ArrayRef;
@@ -102,40 +102,40 @@ pub enum RankType {
     Percent,
 }
 
-static RANK_DOCUMENTATION: OnceLock<Documentation> = OnceLock::new();
+static RANK_DOCUMENTATION: LazyLock<Documentation> = LazyLock::new(|| {
+    Documentation::builder(
+        DOC_SECTION_RANKING,
+            "Returns the rank of the current row within its partition, allowing \
+            gaps between ranks. This function provides a ranking similar to `row_number`, but \
+            skips ranks for identical values.",
+
+        "rank()")
+        .build()
+});
 
 fn get_rank_doc() -> &'static Documentation {
-    RANK_DOCUMENTATION.get_or_init(|| {
-        Documentation::builder(
-            DOC_SECTION_RANKING,
-                "Returns the rank of the current row within its partition, allowing \
-                gaps between ranks. This function provides a ranking similar to `row_number`, but \
-                skips ranks for identical values.",
-
-            "rank()")
-            .build()
-    })
+    &RANK_DOCUMENTATION
 }
 
-static DENSE_RANK_DOCUMENTATION: OnceLock<Documentation> = OnceLock::new();
+static DENSE_RANK_DOCUMENTATION: LazyLock<Documentation> = LazyLock::new(|| {
+    Documentation::builder(DOC_SECTION_RANKING, "Returns the rank of the current row without gaps. This function ranks \
+            rows in a dense manner, meaning consecutive ranks are assigned even for identical \
+            values.", "dense_rank()")
+        .build()
+});
 
 fn get_dense_rank_doc() -> &'static Documentation {
-    DENSE_RANK_DOCUMENTATION.get_or_init(|| {
-        Documentation::builder(DOC_SECTION_RANKING, "Returns the rank of the current row without gaps. This function ranks \
-                rows in a dense manner, meaning consecutive ranks are assigned even for identical \
-                values.", "dense_rank()")
-            .build()
-    })
+    &DENSE_RANK_DOCUMENTATION
 }
 
-static PERCENT_RANK_DOCUMENTATION: OnceLock<Documentation> = OnceLock::new();
+static PERCENT_RANK_DOCUMENTATION: LazyLock<Documentation> = LazyLock::new(|| {
+    Documentation::builder(DOC_SECTION_RANKING, "Returns the percentage rank of the current row within its partition. \
+            The value ranges from 0 to 1 and is computed as `(rank - 1) / (total_rows - 1)`.", "percent_rank()")
+        .build()
+});
 
 fn get_percent_rank_doc() -> &'static Documentation {
-    PERCENT_RANK_DOCUMENTATION.get_or_init(|| {
-        Documentation::builder(DOC_SECTION_RANKING, "Returns the percentage rank of the current row within its partition. \
-                The value ranges from 0 to 1 and is computed as `(rank - 1) / (total_rows - 1)`.", "percent_rank()")
-            .build()
-    })
+    &PERCENT_RANK_DOCUMENTATION
 }
 
 impl WindowUDFImpl for Rank {
diff --git a/datafusion/substrait/src/logical_plan/consumer.rs b/datafusion/substrait/src/logical_plan/consumer.rs
index da8613781d69..e4984011be43 100644
--- a/datafusion/substrait/src/logical_plan/consumer.rs
+++ b/datafusion/substrait/src/logical_plan/consumer.rs
@@ -3293,7 +3293,7 @@ mod test {
     use datafusion::execution::SessionState;
     use datafusion::prelude::{Expr, SessionContext};
     use datafusion::scalar::ScalarValue;
-    use std::sync::OnceLock;
+    use std::sync::LazyLock;
     use substrait::proto::expression::literal::{
         interval_day_to_second, IntervalCompound, IntervalDayToSecond,
         IntervalYearToMonth, LiteralType,
@@ -3301,11 +3301,12 @@ mod test {
     use substrait::proto::expression::window_function::BoundsType;
     use substrait::proto::expression::Literal;
 
-    static TEST_SESSION_STATE: OnceLock<SessionState> = OnceLock::new();
-    static TEST_EXTENSIONS: OnceLock<Extensions> = OnceLock::new();
+    static TEST_SESSION_STATE: LazyLock<SessionState> =
+        LazyLock::new(|| SessionContext::default().state());
+    static TEST_EXTENSIONS: LazyLock<Extensions> = LazyLock::new(Extensions::default);
     fn test_consumer() -> DefaultSubstraitConsumer<'static> {
-        let extensions = TEST_EXTENSIONS.get_or_init(Extensions::default);
-        let state = TEST_SESSION_STATE.get_or_init(|| SessionContext::default().state());
+        let extensions = &TEST_EXTENSIONS;
+        let state = &TEST_SESSION_STATE;
         DefaultSubstraitConsumer::new(extensions, state)
     }
 
diff --git a/datafusion/substrait/src/logical_plan/producer.rs b/datafusion/substrait/src/logical_plan/producer.rs
index 36e89b8205ea..9dbb246453be 100644
--- a/datafusion/substrait/src/logical_plan/producer.rs
+++ b/datafusion/substrait/src/logical_plan/producer.rs
@@ -2552,13 +2552,14 @@ mod test {
     use datafusion::common::DFSchema;
     use datafusion::execution::{SessionState, SessionStateBuilder};
     use datafusion::prelude::SessionContext;
-    use std::sync::OnceLock;
+    use std::sync::LazyLock;
 
-    static TEST_SESSION_STATE: OnceLock<SessionState> = OnceLock::new();
-    static TEST_EXTENSIONS: OnceLock<Extensions> = OnceLock::new();
+    static TEST_SESSION_STATE: LazyLock<SessionState> =
+        LazyLock::new(|| SessionContext::default().state());
+    static TEST_EXTENSIONS: LazyLock<Extensions> = LazyLock::new(Extensions::default);
     fn test_consumer() -> DefaultSubstraitConsumer<'static> {
-        let extensions = TEST_EXTENSIONS.get_or_init(Extensions::default);
-        let state = TEST_SESSION_STATE.get_or_init(|| SessionContext::default().state());
+        let extensions = &TEST_EXTENSIONS;
+        let state = &TEST_SESSION_STATE;
         DefaultSubstraitConsumer::new(extensions, state)
     }
 


Test patch:
diff --git a/datafusion/core/tests/fuzz_cases/pruning.rs b/datafusion/core/tests/fuzz_cases/pruning.rs
index c6876d4a7e96..f87572631b28 100644
--- a/datafusion/core/tests/fuzz_cases/pruning.rs
+++ b/datafusion/core/tests/fuzz_cases/pruning.rs
@@ -15,7 +15,7 @@
 // specific language governing permissions and limitations
 // under the License.
 
-use std::sync::{Arc, OnceLock};
+use std::sync::{Arc, LazyLock};
 
 use arrow::array::{Array, RecordBatch, StringArray};
 use arrow::datatypes::{DataType, Field, Schema};
@@ -204,65 +204,24 @@ impl Utf8Test {
 
     ///  all combinations of interesting charactes  with lengths ranging from 1 to 4
     fn values() -> &'static [String] {
-        VALUES.get_or_init(|| {
-            let mut rng = rand::thread_rng();
-
-            let characters = [
-                "z",
-                "0",
-                "~",
-                "ß",
-                "℣",
-                "%", // this one is useful for like/not like tests since it will result in randomly inserted wildcards
-                "_", // this one is useful for like/not like tests since it will result in randomly inserted wildcards
-                "\u{7F}",
-                "\u{7FF}",
-                "\u{FF}",
-                "\u{10FFFF}",
-                "\u{D7FF}",
-                "\u{FDCF}",
-                // null character
-                "\u{0}",
-            ];
-            let value_lengths = [1, 2, 3];
-            let mut values = vec![];
-            for length in &value_lengths {
-                values.extend(
-                    characters
-                        .iter()
-                        .cloned()
-                        .combinations(*length)
-                        // now get all permutations of each combination
-                        .flat_map(|c| c.into_iter().permutations(*length))
-                        // and join them into strings
-                        .map(|c| c.join("")),
-                );
-            }
-            println!("Generated {} values", values.len());
-            // randomly pick 100 values
-            values.shuffle(&mut rng);
-            values.truncate(100);
-            values
-        })
+        &VALUES
     }
 
     /// return the in memory object store
     fn memory_store() -> &'static Arc<dyn ObjectStore> {
-        MEMORY_STORE.get_or_init(|| Arc::new(InMemory::new()))
+        &MEMORY_STORE
     }
 
     /// return the schema of the created test files
     fn schema() -> Arc<Schema> {
-        let schema = SCHEMA.get_or_init(|| {
-            Arc::new(Schema::new(vec![Field::new("a", DataType::Utf8, false)]))
-        });
+        let schema = &SCHEMA;
         Arc::clone(schema)
     }
 
     /// Return a list of test files with UTF8 data and combinations of
     /// [`Self::values`]
     async fn test_files() -> Vec<TestFile> {
-        let files_mutex = TESTFILES.get_or_init(|| Mutex::new(vec![]));
+        let files_mutex = &TESTFILES;
         let mut files = files_mutex.lock().await;
         if !files.is_empty() {
             return (*files).clone();
@@ -385,16 +344,57 @@ async fn write_parquet_file(
 }
 
 /// The string values for [Utf8Test::values]
-static VALUES: OnceLock<Vec<String>> = OnceLock::new();
+static VALUES: LazyLock<Vec<String>> = LazyLock::new(|| {
+    let mut rng = rand::thread_rng();
+
+    let characters = [
+        "z",
+        "0",
+        "~",
+        "ß",
+        "℣",
+        "%", // this one is useful for like/not like tests since it will result in randomly inserted wildcards
+        "_", // this one is useful for like/not like tests since it will result in randomly inserted wildcards
+        "\u{7F}",
+        "\u{7FF}",
+        "\u{FF}",
+        "\u{10FFFF}",
+        "\u{D7FF}",
+        "\u{FDCF}",
+        // null character
+        "\u{0}",
+    ];
+    let value_lengths = [1, 2, 3];
+    let mut values = vec![];
+    for length in &value_lengths {
+        values.extend(
+            characters
+                .iter()
+                .cloned()
+                .combinations(*length)
+                // now get all permutations of each combination
+                .flat_map(|c| c.into_iter().permutations(*length))
+                // and join them into strings
+                .map(|c| c.join("")),
+        );
+    }
+    println!("Generated {} values", values.len());
+    // randomly pick 100 values
+    values.shuffle(&mut rng);
+    values.truncate(100);
+    values
+});
 /// The schema for the [Utf8Test::schema]
-static SCHEMA: OnceLock<Arc<Schema>> = OnceLock::new();
+static SCHEMA: LazyLock<Arc<Schema>> =
+    LazyLock::new(|| Arc::new(Schema::new(vec![Field::new("a", DataType::Utf8, false)])));
 
 /// The InMemory object store
-static MEMORY_STORE: OnceLock<Arc<dyn ObjectStore>> = OnceLock::new();
+static MEMORY_STORE: LazyLock<Arc<dyn ObjectStore>> =
+    LazyLock::new(|| Arc::new(InMemory::new()));
 
 /// List of in memory parquet files with UTF8 data
-// Use a mutex rather than OnceLock to allow for async initialization
-static TESTFILES: OnceLock<Mutex<Vec<TestFile>>> = OnceLock::new();
+// Use a mutex rather than LazyLock to allow for async initialization
+static TESTFILES: LazyLock<Mutex<Vec<TestFile>>> = LazyLock::new(|| Mutex::new(vec![]));
 
 /// Holds a temporary parquet file path and its size
 #[derive(Debug, Clone)]