From 1a267d029805daa7b6c26b17a0efa9b6d3289d68 Mon Sep 17 00:00:00 2001 From: Nicholas Barbier Date: Sun, 9 Nov 2025 13:25:10 -0500 Subject: [PATCH 1/6] Replace once_cell with std LazyLock and OnceLock MSRV bump to 1.83 enables using standard library equivalents. This removes the external once_cell dependency. Changes: - Replace once_cell::sync::Lazy with std::sync::LazyLock - Replace once_cell::sync::OnceCell with std::sync::OnceLock - Update try_insert() pattern in pingora-runtime to use set() - Remove once_cell from workspace and crate dependencies Fixes #721 --- Cargo.toml | 1 - pingora-cache/Cargo.toml | 1 - pingora-cache/src/cache_control.rs | 6 ++--- pingora-cache/src/memory.rs | 12 +++++----- pingora-cache/src/meta.rs | 6 ++--- pingora-cache/src/put.rs | 4 ++-- pingora-core/Cargo.toml | 1 - pingora-core/src/connectors/offload.rs | 6 ++--- pingora-core/src/modules/http/mod.rs | 6 ++--- pingora-core/src/protocols/digest.rs | 20 ++++++++-------- .../src/protocols/http/compression/mod.rs | 4 ++-- pingora-core/src/protocols/http/error_resp.rs | 6 ++--- pingora-core/src/protocols/http/v1/server.rs | 6 ++--- pingora-core/tests/utils/mod.rs | 4 ++-- pingora-memory-cache/Cargo.toml | 1 - pingora-memory-cache/src/read_through.rs | 10 ++++---- pingora-proxy/Cargo.toml | 1 - pingora-proxy/examples/rate_limiter.rs | 4 ++-- pingora-proxy/src/lib.rs | 4 ++-- pingora-proxy/src/proxy_cache.rs | 5 ++-- pingora-proxy/src/proxy_purge.rs | 9 +++---- pingora-proxy/tests/utils/cert.rs | 24 +++++++++---------- pingora-proxy/tests/utils/mock_origin.rs | 4 ++-- pingora-proxy/tests/utils/mod.rs | 6 ++--- pingora-proxy/tests/utils/server_utils.rs | 20 ++++++++-------- pingora-proxy/tests/utils/websocket.rs | 4 ++-- pingora-runtime/Cargo.toml | 1 - pingora-runtime/src/lib.rs | 20 ++++++++-------- pingora-timeout/Cargo.toml | 1 - pingora-timeout/src/fast_timeout.rs | 4 ++-- pingora/Cargo.toml | 1 - pingora/examples/app/echo.rs | 6 ++--- 32 files changed, 101 insertions(+), 107 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index ce057972..78d1626b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -37,7 +37,6 @@ derivative = "2.2.0" http = "1.0.0" log = "0.4" h2 = ">=0.4.11" -once_cell = "1" lru = "0.14" ahash = ">=0.8.9" diff --git a/pingora-cache/Cargo.toml b/pingora-cache/Cargo.toml index cd51b638..a85f442c 100644 --- a/pingora-cache/Cargo.toml +++ b/pingora-cache/Cargo.toml @@ -25,7 +25,6 @@ pingora-lru = { version = "0.6.0", path = "../pingora-lru" } pingora-timeout = { version = "0.6.0", path = "../pingora-timeout" } http = { workspace = true } indexmap = "1" -once_cell = { workspace = true } regex = "1" blake2 = "0.10" serde = { version = "1.0", features = ["derive"] } diff --git a/pingora-cache/src/cache_control.rs b/pingora-cache/src/cache_control.rs index 8083298e..2fc47b0e 100644 --- a/pingora-cache/src/cache_control.rs +++ b/pingora-cache/src/cache_control.rs @@ -19,7 +19,7 @@ use super::*; use http::header::HeaderName; use http::HeaderValue; use indexmap::IndexMap; -use once_cell::sync::Lazy; +use std::sync::LazyLock; use pingora_error::{Error, ErrorType}; use regex::bytes::Regex; use std::num::IntErrorKind; @@ -157,13 +157,13 @@ impl<'a> Iterator for ListValueIter<'a> { // note the `token` implementation excludes disallowed ASCII ranges // and disallowed delimiters: https://datatracker.ietf.org/doc/html/rfc9110#section-5.6.2 // though it does not forbid `obs-text`: %x80-FF -static RE_CACHE_DIRECTIVE: Lazy = +static RE_CACHE_DIRECTIVE: LazyLock = // to break our version down further: // `(?-u)`: unicode support disabled, which puts the regex into "ASCII compatible mode" for specifying literal bytes like \x7F: https://docs.rs/regex/1.10.4/regex/bytes/index.html#syntax // `(?:^|(?:\s*[,;]\s*)`: allow either , or ; as a delimiter // `([^\x00-\x20\(\)<>@,;:\\"/\[\]\?=\{\}\x7F]+)`: token (directive name capture group) // `(?:=((?:[^\x00-\x20\(\)<>@,;:\\"/\[\]\?=\{\}\x7F]+|(?:"(?:[^"\\]|\\.)*"))))`: token OR quoted-string (directive value capture-group) - Lazy::new(|| { + LazyLock::new(|| { Regex::new(r#"(?-u)(?:^|(?:\s*[,;]\s*))([^\x00-\x20\(\)<>@,;:\\"/\[\]\?=\{\}\x7F]+)(?:=((?:[^\x00-\x20\(\)<>@,;:\\"/\[\]\?=\{\}\x7F]+|(?:"(?:[^"\\]|\\.)*"))))?"#).unwrap() }); diff --git a/pingora-cache/src/memory.rs b/pingora-cache/src/memory.rs index 786cf453..23900539 100644 --- a/pingora-cache/src/memory.rs +++ b/pingora-cache/src/memory.rs @@ -427,7 +427,7 @@ impl Storage for MemCache { mod test { use super::*; use cf_rustracing::span::Span; - use once_cell::sync::Lazy; + use std::sync::LazyLock; fn gen_meta() -> CacheMeta { let mut header = ResponseHeader::build(200, None).unwrap(); @@ -445,7 +445,7 @@ mod test { #[tokio::test] async fn test_write_then_read() { - static MEM_CACHE: Lazy = Lazy::new(MemCache::new); + static MEM_CACHE: LazyLock = LazyLock::new(MemCache::new); let span = &Span::inactive().handle(); let key1 = CacheKey::new("", "a", "1"); @@ -482,7 +482,7 @@ mod test { #[tokio::test] async fn test_read_range() { - static MEM_CACHE: Lazy = Lazy::new(MemCache::new); + static MEM_CACHE: LazyLock = LazyLock::new(MemCache::new); let span = &Span::inactive().handle(); let key1 = CacheKey::new("", "a", "1"); @@ -527,7 +527,7 @@ mod test { async fn test_write_while_read() { use futures::FutureExt; - static MEM_CACHE: Lazy = Lazy::new(MemCache::new); + static MEM_CACHE: LazyLock = LazyLock::new(MemCache::new); let span = &Span::inactive().handle(); let key1 = CacheKey::new("", "a", "1"); @@ -594,7 +594,7 @@ mod test { #[tokio::test] async fn test_purge_partial() { - static MEM_CACHE: Lazy = Lazy::new(MemCache::new); + static MEM_CACHE: LazyLock = LazyLock::new(MemCache::new); let cache = &MEM_CACHE; let key = CacheKey::new("", "a", "1").to_compact(); @@ -621,7 +621,7 @@ mod test { #[tokio::test] async fn test_purge_complete() { - static MEM_CACHE: Lazy = Lazy::new(MemCache::new); + static MEM_CACHE: LazyLock = LazyLock::new(MemCache::new); let cache = &MEM_CACHE; let key = CacheKey::new("", "a", "1").to_compact(); diff --git a/pingora-cache/src/meta.rs b/pingora-cache/src/meta.rs index 9c6bd6fc..724acf2d 100644 --- a/pingora-cache/src/meta.rs +++ b/pingora-cache/src/meta.rs @@ -16,7 +16,7 @@ pub use http::Extensions; use log::warn; -use once_cell::sync::{Lazy, OnceCell}; +use std::sync::{LazyLock, OnceLock}; use pingora_error::{Error, ErrorType::*, OrErr, Result}; use pingora_header_serde::HeaderSerde; use pingora_http::{HMap, ResponseHeader}; @@ -568,9 +568,9 @@ impl CacheMetaDefaults { /// The dictionary content for header compression. /// /// Used during initialization of [`HEADER_SERDE`]. -static COMPRESSION_DICT_CONTENT: OnceCell> = OnceCell::new(); +static COMPRESSION_DICT_CONTENT: OnceLock> = OnceLock::new(); -static HEADER_SERDE: Lazy = Lazy::new(|| { +static HEADER_SERDE: LazyLock = LazyLock::new(|| { let dict_opt = if let Some(dict_content) = COMPRESSION_DICT_CONTENT.get() { Some(dict_content.to_vec()) } else { diff --git a/pingora-cache/src/put.rs b/pingora-cache/src/put.rs index 4c82a482..c6d4a3fd 100644 --- a/pingora-cache/src/put.rs +++ b/pingora-cache/src/put.rs @@ -215,7 +215,7 @@ impl CachePutCtx { mod test { use super::*; use cf_rustracing::span::Span; - use once_cell::sync::Lazy; + use std::sync::LazyLock; struct TestCachePut(); impl CachePut for TestCachePut { @@ -227,7 +227,7 @@ mod test { } type TestCachePutCtx = CachePutCtx; - static CACHE_BACKEND: Lazy = Lazy::new(MemCache::new); + static CACHE_BACKEND: LazyLock = LazyLock::new(MemCache::new); #[tokio::test] async fn test_cache_put() { diff --git a/pingora-core/Cargo.toml b/pingora-core/Cargo.toml index 7818db81..0fef3945 100644 --- a/pingora-core/Cargo.toml +++ b/pingora-core/Cargo.toml @@ -38,7 +38,6 @@ log = { workspace = true } h2 = { workspace = true } derivative.workspace = true clap = { version = "3.2.25", features = ["derive"] } -once_cell = { workspace = true } serde = { version = "1.0", features = ["derive"] } serde_yaml = "0.8" strum = "0.26.2" diff --git a/pingora-core/src/connectors/offload.rs b/pingora-core/src/connectors/offload.rs index 06fc0895..a41671e3 100644 --- a/pingora-core/src/connectors/offload.rs +++ b/pingora-core/src/connectors/offload.rs @@ -13,7 +13,7 @@ // limitations under the License. use log::debug; -use once_cell::sync::OnceCell; +use std::sync::OnceLock; use rand::Rng; use tokio::runtime::{Builder, Handle}; use tokio::sync::oneshot::{channel, Sender}; @@ -25,7 +25,7 @@ pub(crate) struct OffloadRuntime { thread_per_shard: usize, // Lazily init the runtimes so that they are created after pingora // daemonize itself. Otherwise the runtime threads are lost. - pools: OnceCell)]>>, + pools: OnceLock)]>>, } impl OffloadRuntime { @@ -35,7 +35,7 @@ impl OffloadRuntime { OffloadRuntime { shards, thread_per_shard, - pools: OnceCell::new(), + pools: OnceLock::new(), } } diff --git a/pingora-core/src/modules/http/mod.rs b/pingora-core/src/modules/http/mod.rs index d220e6b0..6bf6098b 100644 --- a/pingora-core/src/modules/http/mod.rs +++ b/pingora-core/src/modules/http/mod.rs @@ -26,7 +26,7 @@ pub mod grpc_web; use async_trait::async_trait; use bytes::Bytes; use http::HeaderMap; -use once_cell::sync::OnceCell; +use std::sync::OnceLock; use pingora_error::Result; use pingora_http::{RequestHeader, ResponseHeader}; use std::any::Any; @@ -101,7 +101,7 @@ pub type ModuleBuilder = Box; /// The object to hold multiple http modules pub struct HttpModules { modules: Vec, - module_index: OnceCell>>, + module_index: OnceLock>>, } impl HttpModules { @@ -109,7 +109,7 @@ impl HttpModules { pub fn new() -> Self { HttpModules { modules: vec![], - module_index: OnceCell::new(), + module_index: OnceLock::new(), } } diff --git a/pingora-core/src/protocols/digest.rs b/pingora-core/src/protocols/digest.rs index f939bb1f..1858535a 100644 --- a/pingora-core/src/protocols/digest.rs +++ b/pingora-core/src/protocols/digest.rs @@ -17,7 +17,7 @@ use std::sync::Arc; use std::time::{Duration, SystemTime}; -use once_cell::sync::OnceCell; +use std::sync::OnceLock; use super::l4::ext::{get_original_dest, get_recv_buf, get_snd_buf, get_tcp_info, TCP_INFO}; use super::l4::socket::SocketAddr; @@ -67,11 +67,11 @@ pub struct SocketDigest { #[cfg(windows)] raw_sock: std::os::windows::io::RawSocket, /// Remote socket address - pub peer_addr: OnceCell>, + pub peer_addr: OnceLock>, /// Local socket address - pub local_addr: OnceCell>, + pub local_addr: OnceLock>, /// Original destination address - pub original_dst: OnceCell>, + pub original_dst: OnceLock>, } impl SocketDigest { @@ -79,9 +79,9 @@ impl SocketDigest { pub fn from_raw_fd(raw_fd: std::os::unix::io::RawFd) -> SocketDigest { SocketDigest { raw_fd, - peer_addr: OnceCell::new(), - local_addr: OnceCell::new(), - original_dst: OnceCell::new(), + peer_addr: OnceLock::new(), + local_addr: OnceLock::new(), + original_dst: OnceLock::new(), } } @@ -89,9 +89,9 @@ impl SocketDigest { pub fn from_raw_socket(raw_sock: std::os::windows::io::RawSocket) -> SocketDigest { SocketDigest { raw_sock, - peer_addr: OnceCell::new(), - local_addr: OnceCell::new(), - original_dst: OnceCell::new(), + peer_addr: OnceLock::new(), + local_addr: OnceLock::new(), + original_dst: OnceLock::new(), } } diff --git a/pingora-core/src/protocols/http/compression/mod.rs b/pingora-core/src/protocols/http/compression/mod.rs index 2f86efce..0684a625 100644 --- a/pingora-core/src/protocols/http/compression/mod.rs +++ b/pingora-core/src/protocols/http/compression/mod.rs @@ -616,12 +616,12 @@ fn test_decide_action() { assert_eq!(decide_action(&header, &[Brotli, Gzip]), Noop); } -use once_cell::sync::Lazy; +use std::sync::LazyLock; use regex::Regex; // Allow text, application, font, a few image/ MIME types and binary/octet-stream // TODO: fine tune this list -static MIME_CHECK: Lazy = Lazy::new(|| { +static MIME_CHECK: LazyLock = LazyLock::new(|| { Regex::new(r"^(?:text/|application/|font/|image/(?:x-icon|svg\+xml|nd\.microsoft\.icon)|binary/octet-stream)") .unwrap() }); diff --git a/pingora-core/src/protocols/http/error_resp.rs b/pingora-core/src/protocols/http/error_resp.rs index f802d4d0..983e1bfb 100644 --- a/pingora-core/src/protocols/http/error_resp.rs +++ b/pingora-core/src/protocols/http/error_resp.rs @@ -15,7 +15,7 @@ //! Error response generating utilities. use http::header; -use once_cell::sync::Lazy; +use std::sync::LazyLock; use pingora_http::ResponseHeader; use super::SERVER_NAME; @@ -36,6 +36,6 @@ pub fn gen_error_response(code: u16) -> ResponseHeader { } /// Pre-generated 502 response -pub static HTTP_502_RESPONSE: Lazy = Lazy::new(|| gen_error_response(502)); +pub static HTTP_502_RESPONSE: LazyLock = LazyLock::new(|| gen_error_response(502)); /// Pre-generated 400 response -pub static HTTP_400_RESPONSE: Lazy = Lazy::new(|| gen_error_response(400)); +pub static HTTP_400_RESPONSE: LazyLock = LazyLock::new(|| gen_error_response(400)); diff --git a/pingora-core/src/protocols/http/v1/server.rs b/pingora-core/src/protocols/http/v1/server.rs index 073fee41..928d409b 100644 --- a/pingora-core/src/protocols/http/v1/server.rs +++ b/pingora-core/src/protocols/http/v1/server.rs @@ -20,7 +20,7 @@ use http::header::{CONTENT_LENGTH, TRANSFER_ENCODING}; use http::HeaderValue; use http::{header, header::AsHeaderName, Method, Version}; use log::{debug, warn}; -use once_cell::sync::Lazy; +use std::sync::LazyLock; use percent_encoding::{percent_encode, AsciiSet, CONTROLS}; use pingora_error::{Error, ErrorType::*, OrErr, Result}; use pingora_http::{IntoCaseHeaderName, RequestHeader, ResponseHeader}; @@ -1128,8 +1128,8 @@ impl HttpSession { } // Regex to parse request line that has illegal chars in it -static REQUEST_LINE_REGEX: Lazy = - Lazy::new(|| Regex::new(r"^\w+ (?P.+) HTTP/\d(?:\.\d)?").unwrap()); +static REQUEST_LINE_REGEX: LazyLock = + LazyLock::new(|| Regex::new(r"^\w+ (?P.+) HTTP/\d(?:\.\d)?").unwrap()); // the chars httparse considers illegal in URL // Almost https://url.spec.whatwg.org/#query-percent-encode-set + {} diff --git a/pingora-core/tests/utils/mod.rs b/pingora-core/tests/utils/mod.rs index 7062b349..21033519 100644 --- a/pingora-core/tests/utils/mod.rs +++ b/pingora-core/tests/utils/mod.rs @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -use once_cell::sync::Lazy; +use std::sync::LazyLock; use std::{thread, time}; use clap::Parser; @@ -111,7 +111,7 @@ impl MyServer { } } -pub static TEST_SERVER: Lazy = Lazy::new(MyServer::start); +pub static TEST_SERVER: LazyLock = LazyLock::new(MyServer::start); pub fn init() { let _ = *TEST_SERVER; diff --git a/pingora-memory-cache/Cargo.toml b/pingora-memory-cache/Cargo.toml index bb449610..1f3ff33d 100644 --- a/pingora-memory-cache/Cargo.toml +++ b/pingora-memory-cache/Cargo.toml @@ -27,4 +27,3 @@ parking_lot = "0" pingora-timeout = { version = "0.6.0", path = "../pingora-timeout" } [dev-dependencies] -once_cell = { workspace = true } diff --git a/pingora-memory-cache/src/read_through.rs b/pingora-memory-cache/src/read_through.rs index 140f2362..501778d6 100644 --- a/pingora-memory-cache/src/read_through.rs +++ b/pingora-memory-cache/src/read_through.rs @@ -317,9 +317,9 @@ where /// in the background in order to refresh the value. /// /// Note that this function requires the [RTCache] to be static, which can be done by wrapping - /// it with something like [once_cell::sync::Lazy]. + /// it with something like [std::sync::LazyLock]. /// - /// [once_cell::sync::Lazy]: https://docs.rs/once_cell/latest/once_cell/sync/struct.Lazy.html + /// [std::sync::LazyLock]: https://doc.rust-lang.org/std/sync/struct.LazyLock.html pub async fn get_stale_while_update( &'static self, key: &K, @@ -773,10 +773,10 @@ mod tests { #[tokio::test] async fn test_get_stale_while_update() { - use once_cell::sync::Lazy; + use std::sync::LazyLock; let ttl = Some(Duration::from_millis(100)); - static CACHE: Lazy> = - Lazy::new(|| RTCache::new(10, None, None)); + static CACHE: LazyLock> = + LazyLock::new(|| RTCache::new(10, None, None)); let opt = Some(ExtraOpt { error: false, empty: false, diff --git a/pingora-proxy/Cargo.toml b/pingora-proxy/Cargo.toml index aeaa15eb..468ef36b 100644 --- a/pingora-proxy/Cargo.toml +++ b/pingora-proxy/Cargo.toml @@ -29,7 +29,6 @@ bytes = { workspace = true } async-trait = { workspace = true } log = { workspace = true } h2 = { workspace = true } -once_cell = { workspace = true } clap = { version = "3.2.25", features = ["derive"] } regex = "1" rand = "0.8" diff --git a/pingora-proxy/examples/rate_limiter.rs b/pingora-proxy/examples/rate_limiter.rs index d2c8b7ec..a3121bbf 100644 --- a/pingora-proxy/examples/rate_limiter.rs +++ b/pingora-proxy/examples/rate_limiter.rs @@ -1,5 +1,5 @@ use async_trait::async_trait; -use once_cell::sync::Lazy; +use std::sync::LazyLock; use pingora_core::prelude::*; use pingora_http::{RequestHeader, ResponseHeader}; use pingora_limits::rate::Rate; @@ -50,7 +50,7 @@ impl LB { } // Rate limiter -static RATE_LIMITER: Lazy = Lazy::new(|| Rate::new(Duration::from_secs(1))); +static RATE_LIMITER: LazyLock = LazyLock::new(|| Rate::new(Duration::from_secs(1))); // max request per second per client static MAX_REQ_PER_SEC: isize = 1; diff --git a/pingora-proxy/src/lib.rs b/pingora-proxy/src/lib.rs index d0f41f71..f7ad7222 100644 --- a/pingora-proxy/src/lib.rs +++ b/pingora-proxy/src/lib.rs @@ -40,7 +40,7 @@ use bytes::Bytes; use futures::future::FutureExt; use http::{header, version::Version}; use log::{debug, error, trace, warn}; -use once_cell::sync::Lazy; +use std::sync::LazyLock; use pingora_http::{RequestHeader, ResponseHeader}; use std::fmt::Debug; use std::str; @@ -518,7 +518,7 @@ impl DerefMut for Session { } // generic HTTP 502 response sent when proxy_upstream_filter refuses to connect to upstream -static BAD_GATEWAY: Lazy = Lazy::new(|| { +static BAD_GATEWAY: LazyLock = LazyLock::new(|| { let mut resp = ResponseHeader::build(http::StatusCode::BAD_GATEWAY, Some(3)).unwrap(); resp.insert_header(header::SERVER, &SERVER_NAME[..]) .unwrap(); diff --git a/pingora-proxy/src/proxy_cache.rs b/pingora-proxy/src/proxy_cache.rs index e3d1ba52..c96b59b2 100644 --- a/pingora-proxy/src/proxy_cache.rs +++ b/pingora-proxy/src/proxy_cache.rs @@ -930,10 +930,11 @@ pub mod range_filter { fn parse_range_header(range: &[u8], content_length: usize) -> RangeType { use regex::Regex; + use std::sync::LazyLock; // Match individual range parts, (e.g. "0-100", "-5", "1-") - static RE_SINGLE_RANGE_PART: Lazy = - Lazy::new(|| Regex::new(r"(?i)^\s*(?P\d*)-(?P\d*)\s*$").unwrap()); + static RE_SINGLE_RANGE_PART: LazyLock = + LazyLock::new(|| Regex::new(r"(?i)^\s*(?P\d*)-(?P\d*)\s*$").unwrap()); // Convert bytes to UTF-8 string let range_str = match str::from_utf8(range) { diff --git a/pingora-proxy/src/proxy_purge.rs b/pingora-proxy/src/proxy_purge.rs index 1464aa15..0670f38a 100644 --- a/pingora-proxy/src/proxy_purge.rs +++ b/pingora-proxy/src/proxy_purge.rs @@ -15,6 +15,7 @@ use super::*; use pingora_core::protocols::http::error_resp; use std::borrow::Cow; +use std::sync::LazyLock; #[derive(Debug)] pub enum PurgeStatus { @@ -52,12 +53,12 @@ fn gen_purge_response(code: u16) -> ResponseHeader { resp } -static OK: Lazy = Lazy::new(|| gen_purge_response(200)); -static NOT_FOUND: Lazy = Lazy::new(|| gen_purge_response(404)); +static OK: LazyLock = LazyLock::new(|| gen_purge_response(200)); +static NOT_FOUND: LazyLock = LazyLock::new(|| gen_purge_response(404)); // for when purge is sent to uncacheable assets -static NOT_PURGEABLE: Lazy = Lazy::new(|| gen_purge_response(405)); +static NOT_PURGEABLE: LazyLock = LazyLock::new(|| gen_purge_response(405)); // on cache storage or proxy error -static INTERNAL_ERROR: Lazy = Lazy::new(|| error_resp::gen_error_response(500)); +static INTERNAL_ERROR: LazyLock = LazyLock::new(|| error_resp::gen_error_response(500)); impl HttpProxy { pub(crate) async fn proxy_purge( diff --git a/pingora-proxy/tests/utils/cert.rs b/pingora-proxy/tests/utils/cert.rs index 7594afa4..09e762e6 100644 --- a/pingora-proxy/tests/utils/cert.rs +++ b/pingora-proxy/tests/utils/cert.rs @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -use once_cell::sync::Lazy; +use std::sync::LazyLock; #[cfg(feature = "s2n")] use pingora_core::tls::load_pem_file; #[cfg(feature = "rustls")] @@ -47,17 +47,17 @@ mod key_types { use key_types::*; -pub static INTERMEDIATE_CERT: Lazy = Lazy::new(|| load_cert("keys/intermediate.crt")); -pub static LEAF_CERT: Lazy = Lazy::new(|| load_cert("keys/leaf.crt")); -pub static LEAF2_CERT: Lazy = Lazy::new(|| load_cert("keys/leaf2.crt")); -pub static LEAF_KEY: Lazy = Lazy::new(|| load_key("keys/leaf.key")); -pub static LEAF2_KEY: Lazy = Lazy::new(|| load_key("keys/leaf2.key")); -pub static CURVE_521_TEST_KEY: Lazy = - Lazy::new(|| load_key("keys/curve_test.521.key.pem")); -pub static CURVE_521_TEST_CERT: Lazy = Lazy::new(|| load_cert("keys/curve_test.521.crt")); -pub static CURVE_384_TEST_KEY: Lazy = - Lazy::new(|| load_key("keys/curve_test.384.key.pem")); -pub static CURVE_384_TEST_CERT: Lazy = Lazy::new(|| load_cert("keys/curve_test.384.crt")); +pub static INTERMEDIATE_CERT: LazyLock = LazyLock::new(|| load_cert("keys/intermediate.crt")); +pub static LEAF_CERT: LazyLock = LazyLock::new(|| load_cert("keys/leaf.crt")); +pub static LEAF2_CERT: LazyLock = LazyLock::new(|| load_cert("keys/leaf2.crt")); +pub static LEAF_KEY: LazyLock = LazyLock::new(|| load_key("keys/leaf.key")); +pub static LEAF2_KEY: LazyLock = LazyLock::new(|| load_key("keys/leaf2.key")); +pub static CURVE_521_TEST_KEY: LazyLock = + LazyLock::new(|| load_key("keys/curve_test.521.key.pem")); +pub static CURVE_521_TEST_CERT: LazyLock = LazyLock::new(|| load_cert("keys/curve_test.521.crt")); +pub static CURVE_384_TEST_KEY: LazyLock = + LazyLock::new(|| load_key("keys/curve_test.384.key.pem")); +pub static CURVE_384_TEST_CERT: LazyLock = LazyLock::new(|| load_cert("keys/curve_test.384.crt")); #[cfg(feature = "openssl_derived")] fn load_cert(path: &str) -> X509 { diff --git a/pingora-proxy/tests/utils/mock_origin.rs b/pingora-proxy/tests/utils/mock_origin.rs index f3564dbe..be3ac45b 100644 --- a/pingora-proxy/tests/utils/mock_origin.rs +++ b/pingora-proxy/tests/utils/mock_origin.rs @@ -12,12 +12,12 @@ // See the License for the specific language governing permissions and // limitations under the License. -use once_cell::sync::Lazy; +use std::sync::LazyLock; use std::path::Path; use std::process; use std::{thread, time}; -pub static MOCK_ORIGIN: Lazy = Lazy::new(init); +pub static MOCK_ORIGIN: LazyLock = LazyLock::new(init); fn init() -> bool { #[cfg(feature = "rustls")] diff --git a/pingora-proxy/tests/utils/mod.rs b/pingora-proxy/tests/utils/mod.rs index 7a70ae4f..69538ee6 100644 --- a/pingora-proxy/tests/utils/mod.rs +++ b/pingora-proxy/tests/utils/mod.rs @@ -21,13 +21,13 @@ pub mod mock_origin; pub mod server_utils; pub mod websocket; -use once_cell::sync::Lazy; +use std::sync::LazyLock; use tokio::runtime::{Builder, Runtime}; // for tests with a static connection pool, if we use tokio::test the reactor // will no longer be associated with the backing pool fds since it's dropped per test -pub static GLOBAL_RUNTIME: Lazy = - Lazy::new(|| Builder::new_multi_thread().enable_all().build().unwrap()); +pub static GLOBAL_RUNTIME: LazyLock = + LazyLock::new(|| Builder::new_multi_thread().enable_all().build().unwrap()); pub fn conf_dir() -> String { format!("{}/tests/utils/conf", env!("CARGO_MANIFEST_DIR")) diff --git a/pingora-proxy/tests/utils/server_utils.rs b/pingora-proxy/tests/utils/server_utils.rs index 73629c8d..4c56a5c0 100644 --- a/pingora-proxy/tests/utils/server_utils.rs +++ b/pingora-proxy/tests/utils/server_utils.rs @@ -19,7 +19,7 @@ use clap::Parser; use http::header::{ACCEPT_ENCODING, VARY}; use http::HeaderValue; use log::error; -use once_cell::sync::Lazy; +use std::sync::LazyLock; use pingora_cache::cache_control::CacheControl; use pingora_cache::hashtable::ConcurrentHashTable; use pingora_cache::key::HashBinary; @@ -363,16 +363,16 @@ impl ProxyHttp for ExampleProxyHttp { } } -static CACHE_BACKEND: Lazy = Lazy::new(MemCache::new); +static CACHE_BACKEND: LazyLock = LazyLock::new(MemCache::new); const CACHE_DEFAULT: CacheMetaDefaults = CacheMetaDefaults::new(|_| Some(Duration::from_secs(1)), 1, 1); -static CACHE_PREDICTOR: Lazy> = Lazy::new(|| Predictor::new(5, None)); -static EVICTION_MANAGER: Lazy = Lazy::new(|| Manager::new(8192)); // 8192 bytes -static CACHE_LOCK: Lazy> = - Lazy::new(|| CacheLock::new_boxed(std::time::Duration::from_secs(2))); +static CACHE_PREDICTOR: LazyLock> = LazyLock::new(|| Predictor::new(5, None)); +static EVICTION_MANAGER: LazyLock = LazyLock::new(|| Manager::new(8192)); // 8192 bytes +static CACHE_LOCK: LazyLock> = + LazyLock::new(|| CacheLock::new_boxed(std::time::Duration::from_secs(2))); // Example of how one might restrict which fields can be varied on. -static CACHE_VARY_ALLOWED_HEADERS: Lazy>> = - Lazy::new(|| Some(vec!["accept", "accept-encoding"].into_iter().collect())); +static CACHE_VARY_ALLOWED_HEADERS: LazyLock>> = + LazyLock::new(|| Some(vec!["accept", "accept-encoding"].into_iter().collect())); // #[allow(clippy::upper_case_acronyms)] pub struct CacheCTX { @@ -852,9 +852,9 @@ impl PskTlsServer { } // FIXME: this still allows multiple servers to spawn across integration tests -pub static TEST_SERVER: Lazy = Lazy::new(Server::start); +pub static TEST_SERVER: LazyLock = LazyLock::new(Server::start); #[cfg(feature = "s2n")] -pub static TEST_PSK_TLS_SERVER: Lazy = Lazy::new(PskTlsServer::start); +pub static TEST_PSK_TLS_SERVER: LazyLock = LazyLock::new(PskTlsServer::start); use super::mock_origin::MOCK_ORIGIN; pub fn init() { diff --git a/pingora-proxy/tests/utils/websocket.rs b/pingora-proxy/tests/utils/websocket.rs index 92b35e95..4b4ac6a8 100644 --- a/pingora-proxy/tests/utils/websocket.rs +++ b/pingora-proxy/tests/utils/websocket.rs @@ -2,13 +2,13 @@ use std::{io::Error, thread, time::Duration}; use futures_util::{SinkExt, StreamExt}; use log::debug; -use once_cell::sync::Lazy; +use std::sync::LazyLock; use tokio::{ net::{TcpListener, TcpStream}, runtime::Builder, }; -pub static WS_ECHO: Lazy = Lazy::new(init); +pub static WS_ECHO: LazyLock = LazyLock::new(init); fn init() -> bool { thread::spawn(move || { diff --git a/pingora-runtime/Cargo.toml b/pingora-runtime/Cargo.toml index de419400..f2e0983b 100644 --- a/pingora-runtime/Cargo.toml +++ b/pingora-runtime/Cargo.toml @@ -19,7 +19,6 @@ path = "src/lib.rs" [dependencies] rand = "0.8" tokio = { workspace = true, features = ["rt-multi-thread", "sync", "time"] } -once_cell = { workspace = true } thread_local = "1" [dev-dependencies] diff --git a/pingora-runtime/src/lib.rs b/pingora-runtime/src/lib.rs index 07883400..edf6fac5 100644 --- a/pingora-runtime/src/lib.rs +++ b/pingora-runtime/src/lib.rs @@ -23,7 +23,7 @@ //! This flavor is as efficient as the single-threaded runtime while allows the async //! program to use multiple cores. -use once_cell::sync::{Lazy, OnceCell}; +use std::sync::{LazyLock, OnceLock}; use rand::Rng; use std::sync::Arc; use std::thread::JoinHandle; @@ -83,7 +83,7 @@ impl Runtime { } // only NoStealRuntime set the pools in thread threads -static CURRENT_HANDLE: Lazy> = Lazy::new(ThreadLocal::new); +static CURRENT_HANDLE: LazyLock> = LazyLock::new(ThreadLocal::new); /// Return the [Handle] of current runtime. /// If the current thread is under a `Steal` runtime, the current [Handle] is returned. @@ -103,7 +103,7 @@ pub fn current_handle() -> Handle { } type Control = (Sender, JoinHandle<()>); -type Pools = Arc>>; +type Pools = Arc>>; /// Multi-threaded runtime backed by a pool of single threaded tokio runtime pub struct NoStealRuntime { @@ -112,7 +112,7 @@ pub struct NoStealRuntime { // Lazily init the runtimes so that they are created after pingora // daemonize itself. Otherwise the runtime threads are lost. pools: Pools, - controls: OnceCell>, + controls: OnceLock>, } impl NoStealRuntime { @@ -122,8 +122,8 @@ impl NoStealRuntime { NoStealRuntime { threads, name: name.to_string(), - pools: Arc::new(OnceCell::new()), - controls: OnceCell::new(), + pools: Arc::new(OnceLock::new()), + controls: OnceLock::new(), } } @@ -171,14 +171,14 @@ impl NoStealRuntime { // TODO: use a mutex to avoid creating a lot threads only to drop them let (pools, controls) = self.init_pools(); // there could be another thread racing with this one to init the pools - match self.pools.try_insert(pools) { - Ok(p) => { + match self.pools.set(pools) { + Ok(()) => { // unwrap to make sure that this is the one that init both pools and controls self.controls.set(controls).unwrap(); - p + self.pools.get().unwrap() } // another thread already set it, just return it - Err((p, _my_pools)) => p, + Err(_) => self.pools.get().unwrap(), } } } diff --git a/pingora-timeout/Cargo.toml b/pingora-timeout/Cargo.toml index ff14283c..7cfefd90 100644 --- a/pingora-timeout/Cargo.toml +++ b/pingora-timeout/Cargo.toml @@ -24,7 +24,6 @@ tokio = { workspace = true, features = [ "sync", ] } pin-project-lite = "0.2" -once_cell = { workspace = true } parking_lot = "0.12" thread_local = "1.0" diff --git a/pingora-timeout/src/fast_timeout.rs b/pingora-timeout/src/fast_timeout.rs index 8fd22908..f5d6f754 100644 --- a/pingora-timeout/src/fast_timeout.rs +++ b/pingora-timeout/src/fast_timeout.rs @@ -26,10 +26,10 @@ use super::timer::*; use super::*; -use once_cell::sync::Lazy; +use std::sync::LazyLock; use std::sync::Arc; -static TIMER_MANAGER: Lazy> = Lazy::new(|| { +static TIMER_MANAGER: LazyLock> = LazyLock::new(|| { let tm = Arc::new(TimerManager::new()); check_clock_thread(&tm); tm diff --git a/pingora/Cargo.toml b/pingora/Cargo.toml index 864ae306..5b0cd1bf 100644 --- a/pingora/Cargo.toml +++ b/pingora/Cargo.toml @@ -43,7 +43,6 @@ async-trait = { workspace = true } http = { workspace = true } log = { workspace = true } prometheus = "0.13" -once_cell = { workspace = true } bytes = { workspace = true } regex = "1" diff --git a/pingora/examples/app/echo.rs b/pingora/examples/app/echo.rs index 97e449df..95acc1cc 100644 --- a/pingora/examples/app/echo.rs +++ b/pingora/examples/app/echo.rs @@ -16,7 +16,7 @@ use async_trait::async_trait; use bytes::Bytes; use http::{Response, StatusCode}; use log::debug; -use once_cell::sync::Lazy; +use std::sync::LazyLock; use pingora_timeout::timeout; use prometheus::{register_int_counter, IntCounter}; use std::sync::Arc; @@ -29,8 +29,8 @@ use pingora::protocols::http::ServerSession; use pingora::protocols::Stream; use pingora::server::ShutdownWatch; -static REQ_COUNTER: Lazy = - Lazy::new(|| register_int_counter!("reg_counter", "Number of requests").unwrap()); +static REQ_COUNTER: LazyLock = + LazyLock::new(|| register_int_counter!("reg_counter", "Number of requests").unwrap()); #[derive(Clone)] pub struct EchoApp; From ee221e421054eda4efd3b73fecf08223f9fd10dd Mon Sep 17 00:00:00 2001 From: Nicholas Barbier Date: Sun, 9 Nov 2025 14:20:08 -0500 Subject: [PATCH 2/6] Run cargo fmt to fix import ordering --- pingora-cache/src/cache_control.rs | 2 +- pingora-cache/src/meta.rs | 2 +- pingora-core/src/connectors/offload.rs | 2 +- pingora-core/src/modules/http/mod.rs | 2 +- pingora-core/src/protocols/http/compression/mod.rs | 2 +- pingora-core/src/protocols/http/error_resp.rs | 2 +- pingora-core/src/protocols/http/v1/server.rs | 2 +- pingora-proxy/examples/rate_limiter.rs | 2 +- pingora-proxy/src/lib.rs | 2 +- pingora-proxy/src/proxy_purge.rs | 3 ++- pingora-proxy/tests/utils/cert.rs | 11 +++++++---- pingora-proxy/tests/utils/mock_origin.rs | 2 +- pingora-proxy/tests/utils/server_utils.rs | 2 +- pingora-runtime/src/lib.rs | 2 +- pingora-timeout/src/fast_timeout.rs | 2 +- pingora/examples/app/echo.rs | 2 +- 16 files changed, 23 insertions(+), 19 deletions(-) diff --git a/pingora-cache/src/cache_control.rs b/pingora-cache/src/cache_control.rs index 2fc47b0e..07028579 100644 --- a/pingora-cache/src/cache_control.rs +++ b/pingora-cache/src/cache_control.rs @@ -19,12 +19,12 @@ use super::*; use http::header::HeaderName; use http::HeaderValue; use indexmap::IndexMap; -use std::sync::LazyLock; use pingora_error::{Error, ErrorType}; use regex::bytes::Regex; use std::num::IntErrorKind; use std::slice; use std::str; +use std::sync::LazyLock; /// The max delta-second per [RFC 9111](https://datatracker.ietf.org/doc/html/rfc9111#section-1.2.2) // "If a cache receives a delta-seconds value diff --git a/pingora-cache/src/meta.rs b/pingora-cache/src/meta.rs index 724acf2d..7a66c930 100644 --- a/pingora-cache/src/meta.rs +++ b/pingora-cache/src/meta.rs @@ -16,12 +16,12 @@ pub use http::Extensions; use log::warn; -use std::sync::{LazyLock, OnceLock}; use pingora_error::{Error, ErrorType::*, OrErr, Result}; use pingora_header_serde::HeaderSerde; use pingora_http::{HMap, ResponseHeader}; use serde::{Deserialize, Serialize}; use std::borrow::Cow; +use std::sync::{LazyLock, OnceLock}; use std::time::{Duration, SystemTime}; use crate::key::HashBinary; diff --git a/pingora-core/src/connectors/offload.rs b/pingora-core/src/connectors/offload.rs index a41671e3..bf438232 100644 --- a/pingora-core/src/connectors/offload.rs +++ b/pingora-core/src/connectors/offload.rs @@ -13,8 +13,8 @@ // limitations under the License. use log::debug; -use std::sync::OnceLock; use rand::Rng; +use std::sync::OnceLock; use tokio::runtime::{Builder, Handle}; use tokio::sync::oneshot::{channel, Sender}; diff --git a/pingora-core/src/modules/http/mod.rs b/pingora-core/src/modules/http/mod.rs index 6bf6098b..17a898bd 100644 --- a/pingora-core/src/modules/http/mod.rs +++ b/pingora-core/src/modules/http/mod.rs @@ -26,13 +26,13 @@ pub mod grpc_web; use async_trait::async_trait; use bytes::Bytes; use http::HeaderMap; -use std::sync::OnceLock; use pingora_error::Result; use pingora_http::{RequestHeader, ResponseHeader}; use std::any::Any; use std::any::TypeId; use std::collections::HashMap; use std::sync::Arc; +use std::sync::OnceLock; /// The trait an HTTP traffic module needs to implement #[async_trait] diff --git a/pingora-core/src/protocols/http/compression/mod.rs b/pingora-core/src/protocols/http/compression/mod.rs index 0684a625..406b8a1c 100644 --- a/pingora-core/src/protocols/http/compression/mod.rs +++ b/pingora-core/src/protocols/http/compression/mod.rs @@ -616,8 +616,8 @@ fn test_decide_action() { assert_eq!(decide_action(&header, &[Brotli, Gzip]), Noop); } -use std::sync::LazyLock; use regex::Regex; +use std::sync::LazyLock; // Allow text, application, font, a few image/ MIME types and binary/octet-stream // TODO: fine tune this list diff --git a/pingora-core/src/protocols/http/error_resp.rs b/pingora-core/src/protocols/http/error_resp.rs index 983e1bfb..e34a9939 100644 --- a/pingora-core/src/protocols/http/error_resp.rs +++ b/pingora-core/src/protocols/http/error_resp.rs @@ -15,8 +15,8 @@ //! Error response generating utilities. use http::header; -use std::sync::LazyLock; use pingora_http::ResponseHeader; +use std::sync::LazyLock; use super::SERVER_NAME; diff --git a/pingora-core/src/protocols/http/v1/server.rs b/pingora-core/src/protocols/http/v1/server.rs index 928d409b..813c759e 100644 --- a/pingora-core/src/protocols/http/v1/server.rs +++ b/pingora-core/src/protocols/http/v1/server.rs @@ -20,12 +20,12 @@ use http::header::{CONTENT_LENGTH, TRANSFER_ENCODING}; use http::HeaderValue; use http::{header, header::AsHeaderName, Method, Version}; use log::{debug, warn}; -use std::sync::LazyLock; use percent_encoding::{percent_encode, AsciiSet, CONTROLS}; use pingora_error::{Error, ErrorType::*, OrErr, Result}; use pingora_http::{IntoCaseHeaderName, RequestHeader, ResponseHeader}; use pingora_timeout::timeout; use regex::bytes::Regex; +use std::sync::LazyLock; use std::time::Duration; use tokio::io::{AsyncReadExt, AsyncWriteExt}; diff --git a/pingora-proxy/examples/rate_limiter.rs b/pingora-proxy/examples/rate_limiter.rs index a3121bbf..87a4b34b 100644 --- a/pingora-proxy/examples/rate_limiter.rs +++ b/pingora-proxy/examples/rate_limiter.rs @@ -1,5 +1,4 @@ use async_trait::async_trait; -use std::sync::LazyLock; use pingora_core::prelude::*; use pingora_http::{RequestHeader, ResponseHeader}; use pingora_limits::rate::Rate; @@ -7,6 +6,7 @@ use pingora_load_balancing::prelude::{RoundRobin, TcpHealthCheck}; use pingora_load_balancing::LoadBalancer; use pingora_proxy::{http_proxy_service, ProxyHttp, Session}; use std::sync::Arc; +use std::sync::LazyLock; use std::time::Duration; fn main() { diff --git a/pingora-proxy/src/lib.rs b/pingora-proxy/src/lib.rs index f7ad7222..6efe09a2 100644 --- a/pingora-proxy/src/lib.rs +++ b/pingora-proxy/src/lib.rs @@ -40,11 +40,11 @@ use bytes::Bytes; use futures::future::FutureExt; use http::{header, version::Version}; use log::{debug, error, trace, warn}; -use std::sync::LazyLock; use pingora_http::{RequestHeader, ResponseHeader}; use std::fmt::Debug; use std::str; use std::sync::Arc; +use std::sync::LazyLock; use std::time::Duration; use tokio::sync::{mpsc, Notify}; use tokio::time; diff --git a/pingora-proxy/src/proxy_purge.rs b/pingora-proxy/src/proxy_purge.rs index 0670f38a..457205fb 100644 --- a/pingora-proxy/src/proxy_purge.rs +++ b/pingora-proxy/src/proxy_purge.rs @@ -58,7 +58,8 @@ static NOT_FOUND: LazyLock = LazyLock::new(|| gen_purge_response // for when purge is sent to uncacheable assets static NOT_PURGEABLE: LazyLock = LazyLock::new(|| gen_purge_response(405)); // on cache storage or proxy error -static INTERNAL_ERROR: LazyLock = LazyLock::new(|| error_resp::gen_error_response(500)); +static INTERNAL_ERROR: LazyLock = + LazyLock::new(|| error_resp::gen_error_response(500)); impl HttpProxy { pub(crate) async fn proxy_purge( diff --git a/pingora-proxy/tests/utils/cert.rs b/pingora-proxy/tests/utils/cert.rs index 09e762e6..69a60582 100644 --- a/pingora-proxy/tests/utils/cert.rs +++ b/pingora-proxy/tests/utils/cert.rs @@ -12,7 +12,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -use std::sync::LazyLock; #[cfg(feature = "s2n")] use pingora_core::tls::load_pem_file; #[cfg(feature = "rustls")] @@ -23,6 +22,7 @@ use pingora_core::tls::{ x509::X509, }; use std::fs; +use std::sync::LazyLock; #[cfg(feature = "openssl_derived")] mod key_types { @@ -47,17 +47,20 @@ mod key_types { use key_types::*; -pub static INTERMEDIATE_CERT: LazyLock = LazyLock::new(|| load_cert("keys/intermediate.crt")); +pub static INTERMEDIATE_CERT: LazyLock = + LazyLock::new(|| load_cert("keys/intermediate.crt")); pub static LEAF_CERT: LazyLock = LazyLock::new(|| load_cert("keys/leaf.crt")); pub static LEAF2_CERT: LazyLock = LazyLock::new(|| load_cert("keys/leaf2.crt")); pub static LEAF_KEY: LazyLock = LazyLock::new(|| load_key("keys/leaf.key")); pub static LEAF2_KEY: LazyLock = LazyLock::new(|| load_key("keys/leaf2.key")); pub static CURVE_521_TEST_KEY: LazyLock = LazyLock::new(|| load_key("keys/curve_test.521.key.pem")); -pub static CURVE_521_TEST_CERT: LazyLock = LazyLock::new(|| load_cert("keys/curve_test.521.crt")); +pub static CURVE_521_TEST_CERT: LazyLock = + LazyLock::new(|| load_cert("keys/curve_test.521.crt")); pub static CURVE_384_TEST_KEY: LazyLock = LazyLock::new(|| load_key("keys/curve_test.384.key.pem")); -pub static CURVE_384_TEST_CERT: LazyLock = LazyLock::new(|| load_cert("keys/curve_test.384.crt")); +pub static CURVE_384_TEST_CERT: LazyLock = + LazyLock::new(|| load_cert("keys/curve_test.384.crt")); #[cfg(feature = "openssl_derived")] fn load_cert(path: &str) -> X509 { diff --git a/pingora-proxy/tests/utils/mock_origin.rs b/pingora-proxy/tests/utils/mock_origin.rs index be3ac45b..360e9ee4 100644 --- a/pingora-proxy/tests/utils/mock_origin.rs +++ b/pingora-proxy/tests/utils/mock_origin.rs @@ -12,9 +12,9 @@ // See the License for the specific language governing permissions and // limitations under the License. -use std::sync::LazyLock; use std::path::Path; use std::process; +use std::sync::LazyLock; use std::{thread, time}; pub static MOCK_ORIGIN: LazyLock = LazyLock::new(init); diff --git a/pingora-proxy/tests/utils/server_utils.rs b/pingora-proxy/tests/utils/server_utils.rs index 4c56a5c0..d6b4a18e 100644 --- a/pingora-proxy/tests/utils/server_utils.rs +++ b/pingora-proxy/tests/utils/server_utils.rs @@ -19,7 +19,6 @@ use clap::Parser; use http::header::{ACCEPT_ENCODING, VARY}; use http::HeaderValue; use log::error; -use std::sync::LazyLock; use pingora_cache::cache_control::CacheControl; use pingora_cache::hashtable::ConcurrentHashTable; use pingora_cache::key::HashBinary; @@ -46,6 +45,7 @@ use pingora_http::{RequestHeader, ResponseHeader}; use pingora_proxy::{FailToProxy, ProxyHttp, Session}; use std::collections::{HashMap, HashSet}; use std::sync::Arc; +use std::sync::LazyLock; use std::thread; use std::time::Duration; diff --git a/pingora-runtime/src/lib.rs b/pingora-runtime/src/lib.rs index edf6fac5..25dec5ca 100644 --- a/pingora-runtime/src/lib.rs +++ b/pingora-runtime/src/lib.rs @@ -23,9 +23,9 @@ //! This flavor is as efficient as the single-threaded runtime while allows the async //! program to use multiple cores. -use std::sync::{LazyLock, OnceLock}; use rand::Rng; use std::sync::Arc; +use std::sync::{LazyLock, OnceLock}; use std::thread::JoinHandle; use std::time::Duration; use thread_local::ThreadLocal; diff --git a/pingora-timeout/src/fast_timeout.rs b/pingora-timeout/src/fast_timeout.rs index f5d6f754..1fc41288 100644 --- a/pingora-timeout/src/fast_timeout.rs +++ b/pingora-timeout/src/fast_timeout.rs @@ -26,8 +26,8 @@ use super::timer::*; use super::*; -use std::sync::LazyLock; use std::sync::Arc; +use std::sync::LazyLock; static TIMER_MANAGER: LazyLock> = LazyLock::new(|| { let tm = Arc::new(TimerManager::new()); diff --git a/pingora/examples/app/echo.rs b/pingora/examples/app/echo.rs index 95acc1cc..7da93b60 100644 --- a/pingora/examples/app/echo.rs +++ b/pingora/examples/app/echo.rs @@ -16,10 +16,10 @@ use async_trait::async_trait; use bytes::Bytes; use http::{Response, StatusCode}; use log::debug; -use std::sync::LazyLock; use pingora_timeout::timeout; use prometheus::{register_int_counter, IntCounter}; use std::sync::Arc; +use std::sync::LazyLock; use std::time::Duration; use tokio::io::{AsyncReadExt, AsyncWriteExt}; From e9a6a1ae4d996aeee5ad65aa99bd2d8dc3ad5f91 Mon Sep 17 00:00:00 2001 From: Nicholas Barbier Date: Sun, 9 Nov 2025 14:43:53 -0500 Subject: [PATCH 3/6] Update MSRV to 1.83 for LazyLock support --- clippy.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy.toml b/clippy.toml index ebba0354..f234c901 100644 --- a/clippy.toml +++ b/clippy.toml @@ -1 +1 @@ -msrv = "1.72" +msrv = "1.83" From 89d61540d8777cab4beaafeb07be044db9984ac1 Mon Sep 17 00:00:00 2001 From: Nicholas Barbier Date: Sun, 9 Nov 2025 15:01:49 -0500 Subject: [PATCH 4/6] Fix clippy warnings for Rust 1.87 --- pingora-core/src/connectors/http/mod.rs | 2 +- pingora-core/src/connectors/http/v2.rs | 2 +- pingora-core/src/protocols/http/subrequest/server.rs | 7 +++---- pingora-core/src/protocols/l4/ext.rs | 5 +---- pingora-core/src/protocols/l4/socket.rs | 3 +-- pingora-error/src/lib.rs | 2 +- 6 files changed, 8 insertions(+), 13 deletions(-) diff --git a/pingora-core/src/connectors/http/mod.rs b/pingora-core/src/connectors/http/mod.rs index 45b14f44..a2f745d7 100644 --- a/pingora-core/src/connectors/http/mod.rs +++ b/pingora-core/src/connectors/http/mod.rs @@ -49,7 +49,7 @@ impl Connector { // We assume no peer option == no ALPN == h1 only let h1_only = peer .get_peer_options() - .map_or(true, |o| o.alpn.get_max_http_version() == 1); + .is_none_or(|o| o.alpn.get_max_http_version() == 1); if h1_only { let (h1, reused) = self.h1.get_http_session(peer).await?; Ok((HttpSession::H1(h1), reused)) diff --git a/pingora-core/src/connectors/http/v2.rs b/pingora-core/src/connectors/http/v2.rs index 92cc31d5..9f8e9557 100644 --- a/pingora-core/src/connectors/http/v2.rs +++ b/pingora-core/src/connectors/http/v2.rs @@ -257,7 +257,7 @@ impl Connector { if peer.tls() || peer .get_peer_options() - .map_or(true, |o| o.alpn.get_min_http_version() == 1) + .is_none_or(|o| o.alpn.get_min_http_version() == 1) { return Ok(HttpSession::H1(Http1Session::new(stream))); } diff --git a/pingora-core/src/protocols/http/subrequest/server.rs b/pingora-core/src/protocols/http/subrequest/server.rs index 691532d8..d9e86adb 100644 --- a/pingora-core/src/protocols/http/subrequest/server.rs +++ b/pingora-core/src/protocols/http/subrequest/server.rs @@ -222,12 +222,11 @@ impl HttpSession { /// Read the request body. `Ok(None)` when there is no (more) body to read. pub async fn read_body_bytes(&mut self) -> Result> { let read = self.read_body().await?; - Ok(read.map(|b| { + Ok(read.inspect(|b| { self.body_bytes_read += b.len(); if let Some(buffer) = self.retry_buffer.as_mut() { - buffer.write_to_buffer(&b); + buffer.write_to_buffer(b); } - b })) } @@ -554,7 +553,7 @@ impl HttpSession { // just consume empty body or done messages, the downstream channel is not a real // connection and only used for this one request while matches!(&task, HttpTask::Done) - || matches!(&task, HttpTask::Body(b, _) if b.as_ref().map_or(true, |b| b.is_empty())) + || matches!(&task, HttpTask::Body(b, _) if b.as_ref().is_none_or(|b| b.is_empty())) { task = rx .recv() diff --git a/pingora-core/src/protocols/l4/ext.rs b/pingora-core/src/protocols/l4/ext.rs index 9f7d8ec4..a380932a 100644 --- a/pingora-core/src/protocols/l4/ext.rs +++ b/pingora-core/src/protocols/l4/ext.rs @@ -154,10 +154,7 @@ fn get_opt_sized(sock: c_int, opt: c_int, val: c_int) -> io::Result { get_opt(sock, opt, val, &mut payload, &mut size)?; if size != expected_size { - return Err(std::io::Error::new( - std::io::ErrorKind::Other, - "get_opt size mismatch", - )); + return Err(std::io::Error::other("get_opt size mismatch")); } // Assume getsockopt() will set the value properly let payload = unsafe { payload.assume_init() }; diff --git a/pingora-core/src/protocols/l4/socket.rs b/pingora-core/src/protocols/l4/socket.rs index 3a764920..258acc4f 100644 --- a/pingora-core/src/protocols/l4/socket.rs +++ b/pingora-core/src/protocols/l4/socket.rs @@ -238,8 +238,7 @@ impl std::net::ToSocketAddrs for SocketAddr { if let Some(inet) = self.as_inet() { Ok(std::iter::once(*inet)) } else { - Err(std::io::Error::new( - std::io::ErrorKind::Other, + Err(std::io::Error::other( "UDS socket cannot be used as inet socket", )) } diff --git a/pingora-error/src/lib.rs b/pingora-error/src/lib.rs index c2d25ad5..93c6649a 100644 --- a/pingora-error/src/lib.rs +++ b/pingora-error/src/lib.rs @@ -38,7 +38,7 @@ pub struct Error { /// if the error is retry-able pub retry: RetryType, /// chain to the cause of this error - pub cause: Option>, + pub cause: Option>, /// an arbitrary string that explains the context when the error happens pub context: Option, } From 291764e037ce386625c0181078dbbf723f61d46f Mon Sep 17 00:00:00 2001 From: Nicholas Barbier Date: Sun, 9 Nov 2025 15:48:24 -0500 Subject: [PATCH 5/6] Fix clippy warnings for Rust 1.87.0 Address clippy lints that were failing in CI: - Replace map_or(true, ...) with is_none_or() per clippy::unnecessary_map_or - Replace io::Error::new(io::ErrorKind::Other, e) with io::Error::other(e) - Fix cfg gate on wait_for_peer to match its only caller - Add cfg gates to imports only used in Linux-specific tests --- pingora-boringssl/src/boring_tokio.rs | 2 +- pingora-cache/src/eviction/simple_lru.rs | 2 +- pingora-cache/src/filters.rs | 2 +- pingora-cache/src/hashtable.rs | 2 +- pingora-cache/src/lib.rs | 2 +- pingora-core/src/connectors/l4.rs | 5 ++++- pingora-proxy/src/lib.rs | 2 +- pingora-proxy/src/proxy_cache.rs | 4 ++-- pingora-proxy/tests/utils/server_utils.rs | 2 +- 9 files changed, 13 insertions(+), 10 deletions(-) diff --git a/pingora-boringssl/src/boring_tokio.rs b/pingora-boringssl/src/boring_tokio.rs index 4dd2f91e..42982fe5 100644 --- a/pingora-boringssl/src/boring_tokio.rs +++ b/pingora-boringssl/src/boring_tokio.rs @@ -265,7 +265,7 @@ where Err(e) => { return Poll::Ready(Err(e .into_io_error() - .unwrap_or_else(|e| io::Error::new(io::ErrorKind::Other, e)))); + .unwrap_or_else(io::Error::other))); } } diff --git a/pingora-cache/src/eviction/simple_lru.rs b/pingora-cache/src/eviction/simple_lru.rs index 3125dfb4..5c1c7429 100644 --- a/pingora-cache/src/eviction/simple_lru.rs +++ b/pingora-cache/src/eviction/simple_lru.rs @@ -124,7 +124,7 @@ impl Manager { if self.used.load(Ordering::Relaxed) <= self.limit && self .items_watermark - .map_or(true, |w| self.items.load(Ordering::Relaxed) <= w) + .is_none_or(|w| self.items.load(Ordering::Relaxed) <= w) { return vec![]; } diff --git a/pingora-cache/src/filters.rs b/pingora-cache/src/filters.rs index 20202ea2..5ad74916 100644 --- a/pingora-cache/src/filters.rs +++ b/pingora-cache/src/filters.rs @@ -89,7 +89,7 @@ pub fn calculate_fresh_until( if authorization_present { let uncacheable = cache_control .as_ref() - .map_or(true, |cc| !cc.allow_caching_authorized_req()); + .is_none_or(|cc| !cc.allow_caching_authorized_req()); if uncacheable { return None; } diff --git a/pingora-cache/src/hashtable.rs b/pingora-cache/src/hashtable.rs index 52292046..56db7761 100644 --- a/pingora-cache/src/hashtable.rs +++ b/pingora-cache/src/hashtable.rs @@ -103,7 +103,7 @@ where pub fn new(shard_capacity: usize) -> Self { use std::num::NonZeroUsize; // safe, 1 != 0 - const ONE: NonZeroUsize = unsafe { NonZeroUsize::new_unchecked(1) }; + const ONE: NonZeroUsize = NonZeroUsize::new(1).unwrap(); let mut cache = ConcurrentLruCache { lrus: Default::default(), }; diff --git a/pingora-cache/src/lib.rs b/pingora-cache/src/lib.rs index 98b466c2..b383e7ce 100644 --- a/pingora-cache/src/lib.rs +++ b/pingora-cache/src/lib.rs @@ -688,7 +688,7 @@ impl HttpCache { self.inner_mut() .max_file_size_tracker .as_mut() - .map_or(true, |t| t.add_body_bytes(bytes_len)) + .is_none_or(|t| t.add_body_bytes(bytes_len)) } /// Check if the max file size has been exceeded according to max file size tracker. diff --git a/pingora-core/src/connectors/l4.rs b/pingora-core/src/connectors/l4.rs index dc442644..1f17279d 100644 --- a/pingora-core/src/connectors/l4.rs +++ b/pingora-core/src/connectors/l4.rs @@ -307,15 +307,18 @@ async fn proxy_connect(peer: &P) -> Result { mod tests { use super::*; use crate::upstreams::peer::{BasicPeer, HttpPeer, Proxy}; + #[cfg(target_os = "linux")] use pingora_error::ErrorType; use std::collections::BTreeMap; use std::path::PathBuf; use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::Arc; + #[cfg(target_os = "linux")] use std::time::{Duration, Instant}; use tokio::io::AsyncWriteExt; #[cfg(unix)] use tokio::net::UnixListener; + #[cfg(target_os = "linux")] use tokio::time::sleep; /// Some of the tests below are flaky when making new connections to mock @@ -323,7 +326,7 @@ mod tests { /// not indicative of real errors. This function will retry the peer/server /// in increasing intervals until it either succeeds in connecting or a long /// timeout expires (max 10sec) - #[cfg(unix)] + #[cfg(target_os = "linux")] async fn wait_for_peer

(peer: &P) where P: Peer + Send + Sync, diff --git a/pingora-proxy/src/lib.rs b/pingora-proxy/src/lib.rs index 6efe09a2..98e937c5 100644 --- a/pingora-proxy/src/lib.rs +++ b/pingora-proxy/src/lib.rs @@ -217,7 +217,7 @@ impl HttpProxy { if matches!(e.etype, H2Downgrade | InvalidH2) { if peer .get_alpn() - .map_or(true, |alpn| alpn.get_min_http_version() == 1) + .is_none_or(|alpn| alpn.get_min_http_version() == 1) { // Add the peer to prefer h1 so that all following requests // will use h1 diff --git a/pingora-proxy/src/proxy_cache.rs b/pingora-proxy/src/proxy_cache.rs index c96b59b2..16300fca 100644 --- a/pingora-proxy/src/proxy_cache.rs +++ b/pingora-proxy/src/proxy_cache.rs @@ -153,7 +153,7 @@ impl HttpProxy { session.cache.cache_found(meta, handler, hit_status); } - if hit_status_opt.map_or(true, HitStatus::is_treated_as_miss) { + if hit_status_opt.is_none_or(HitStatus::is_treated_as_miss) { // cache miss if session.cache.is_cache_locked() { // Another request is filling the cache; try waiting til that's done and retry. @@ -403,7 +403,7 @@ impl HttpProxy { return (false, Some(e)); } - if !end && body.as_ref().map_or(true, |b| b.is_empty()) { + if !end && body.as_ref().is_none_or(|b| b.is_empty()) { // Don't write empty body which will end session, // still more hit handler bytes to read continue; diff --git a/pingora-proxy/tests/utils/server_utils.rs b/pingora-proxy/tests/utils/server_utils.rs index d6b4a18e..9e4173c7 100644 --- a/pingora-proxy/tests/utils/server_utils.rs +++ b/pingora-proxy/tests/utils/server_utils.rs @@ -696,7 +696,7 @@ impl ProxyHttp for ExampleProxyCache { error: Option<&Error>, // None when it is called during stale while revalidate ) -> bool { // enable serve stale while updating - error.map_or(true, |e| e.esource() == &ErrorSource::Upstream) + error.is_none_or(|e| e.esource() == &ErrorSource::Upstream) } fn is_purge(&self, session: &Session, _ctx: &Self::CTX) -> bool { From d48283a33a05d8fa4d611920a22504bdd05c5366 Mon Sep 17 00:00:00 2001 From: Nicholas Barbier Date: Sun, 9 Nov 2025 16:03:21 -0500 Subject: [PATCH 6/6] Run cargo fmt --- pingora-boringssl/src/boring_tokio.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/pingora-boringssl/src/boring_tokio.rs b/pingora-boringssl/src/boring_tokio.rs index 42982fe5..deb4842c 100644 --- a/pingora-boringssl/src/boring_tokio.rs +++ b/pingora-boringssl/src/boring_tokio.rs @@ -263,9 +263,7 @@ where return Poll::Pending; } Err(e) => { - return Poll::Ready(Err(e - .into_io_error() - .unwrap_or_else(io::Error::other))); + return Poll::Ready(Err(e.into_io_error().unwrap_or_else(io::Error::other))); } }