Line data Source code
1 : // rustc lints/lint groups
2 : // https://doc.rust-lang.org/rustc/lints/groups.html
3 : #![deny(
4 : deprecated,
5 : future_incompatible,
6 : // TODO: consider let_underscore
7 : nonstandard_style,
8 : rust_2024_compatibility
9 : )]
10 : #![warn(clippy::all, clippy::pedantic, clippy::cargo)]
11 : // List of denied lints from the clippy::restriction group.
12 : // https://rust-lang.github.io/rust-clippy/master/index.html#?groups=restriction
13 : #![warn(
14 : clippy::undocumented_unsafe_blocks,
15 : // TODO: Enable once all individual checks are enabled.
16 : //clippy::as_conversions,
17 : clippy::dbg_macro,
18 : clippy::empty_enum_variants_with_brackets,
19 : clippy::exit,
20 : clippy::float_cmp_const,
21 : clippy::lossy_float_literal,
22 : clippy::macro_use_imports,
23 : clippy::manual_ok_or,
24 : // TODO: consider clippy::map_err_ignore
25 : // TODO: consider clippy::mem_forget
26 : clippy::rc_mutex,
27 : clippy::rest_pat_in_fully_bound_structs,
28 : clippy::string_add,
29 : clippy::string_to_string,
30 : clippy::todo,
31 : // TODO: consider clippy::unimplemented
32 : // TODO: consider clippy::unwrap_used
33 : )]
34 : // List of permanently allowed lints.
35 : #![allow(
36 : // It's ok to cast bool to u8, etc.
37 : clippy::cast_lossless,
38 : // Seems unavoidable.
39 : clippy::multiple_crate_versions,
40 : // While #[must_use] is a great feature this check is too noisy.
41 : clippy::must_use_candidate,
42 : // Inline consts, structs, fns, imports, etc. are ok if they're used by
43 : // the following statement(s).
44 : clippy::items_after_statements,
45 : )]
46 : // List of temporarily allowed lints.
47 : // TODO: Switch to except() once stable with 1.81.
48 : // TODO: fix code and reduce list or move to permanent list above.
49 : #![allow(
50 : clippy::cargo_common_metadata,
51 : clippy::cast_possible_truncation,
52 : clippy::cast_possible_wrap,
53 : clippy::cast_precision_loss,
54 : clippy::cast_sign_loss,
55 : clippy::doc_markdown,
56 : clippy::implicit_hasher,
57 : clippy::inline_always,
58 : clippy::match_same_arms,
59 : clippy::match_wild_err_arm,
60 : clippy::missing_errors_doc,
61 : clippy::missing_panics_doc,
62 : clippy::module_name_repetitions,
63 : clippy::needless_pass_by_value,
64 : clippy::needless_raw_string_hashes,
65 : clippy::redundant_closure_for_method_calls,
66 : clippy::return_self_not_must_use,
67 : clippy::similar_names,
68 : clippy::single_match_else,
69 : clippy::struct_excessive_bools,
70 : clippy::struct_field_names,
71 : clippy::too_many_lines,
72 : clippy::unreadable_literal,
73 : clippy::unused_async,
74 : clippy::unused_self,
75 : clippy::wildcard_imports
76 : )]
77 : // List of temporarily allowed lints to unblock beta/nightly.
78 : #![allow(unknown_lints, clippy::manual_inspect)]
79 :
80 : use std::{convert::Infallible, future::Future};
81 :
82 : use anyhow::{bail, Context};
83 : use intern::{EndpointIdInt, EndpointIdTag, InternId};
84 : use tokio::task::JoinError;
85 : use tokio_util::sync::CancellationToken;
86 : use tracing::warn;
87 :
88 : pub mod auth;
89 : pub mod cache;
90 : pub mod cancellation;
91 : pub mod compute;
92 : pub mod config;
93 : pub mod console;
94 : pub mod context;
95 : pub mod error;
96 : pub mod http;
97 : pub mod intern;
98 : pub mod jemalloc;
99 : pub mod logging;
100 : pub mod metrics;
101 : pub mod parse;
102 : pub mod protocol2;
103 : pub mod proxy;
104 : pub mod rate_limiter;
105 : pub mod redis;
106 : pub mod sasl;
107 : pub mod scram;
108 : pub mod serverless;
109 : pub mod stream;
110 : pub mod url;
111 : pub mod usage_metrics;
112 : pub mod waiters;
113 :
114 : /// Handle unix signals appropriately.
115 0 : pub async fn handle_signals<F, Fut>(
116 0 : token: CancellationToken,
117 0 : mut refresh_config: F,
118 0 : ) -> anyhow::Result<Infallible>
119 0 : where
120 0 : F: FnMut() -> Fut,
121 0 : Fut: Future<Output = anyhow::Result<()>>,
122 0 : {
123 : use tokio::signal::unix::{signal, SignalKind};
124 :
125 0 : let mut hangup = signal(SignalKind::hangup())?;
126 0 : let mut interrupt = signal(SignalKind::interrupt())?;
127 0 : let mut terminate = signal(SignalKind::terminate())?;
128 :
129 0 : loop {
130 0 : tokio::select! {
131 : // Hangup is commonly used for config reload.
132 : _ = hangup.recv() => {
133 : warn!("received SIGHUP");
134 : refresh_config().await?;
135 : }
136 : // Shut down the whole application.
137 : _ = interrupt.recv() => {
138 : warn!("received SIGINT, exiting immediately");
139 : bail!("interrupted");
140 : }
141 : _ = terminate.recv() => {
142 : warn!("received SIGTERM, shutting down once all existing connections have closed");
143 : token.cancel();
144 : }
145 0 : }
146 0 : }
147 0 : }
148 :
149 : /// Flattens `Result<Result<T>>` into `Result<T>`.
150 0 : pub fn flatten_err<T>(r: Result<anyhow::Result<T>, JoinError>) -> anyhow::Result<T> {
151 0 : r.context("join error").and_then(|x| x)
152 0 : }
153 :
154 : macro_rules! smol_str_wrapper {
155 : ($name:ident) => {
156 : #[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
157 : pub struct $name(smol_str::SmolStr);
158 :
159 : impl $name {
160 : #[allow(unused)]
161 0 : pub(crate) fn as_str(&self) -> &str {
162 0 : self.0.as_str()
163 0 : }
164 : }
165 :
166 : impl std::fmt::Display for $name {
167 3 : fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
168 3 : self.0.fmt(f)
169 3 : }
170 : }
171 :
172 : impl<T> std::cmp::PartialEq<T> for $name
173 : where
174 : smol_str::SmolStr: std::cmp::PartialEq<T>,
175 : {
176 19 : fn eq(&self, other: &T) -> bool {
177 19 : self.0.eq(other)
178 19 : }
179 : }
180 :
181 : impl<T> From<T> for $name
182 : where
183 : smol_str::SmolStr: From<T>,
184 : {
185 163 : fn from(x: T) -> Self {
186 163 : Self(x.into())
187 163 : }
188 : }
189 :
190 : impl AsRef<str> for $name {
191 10 : fn as_ref(&self) -> &str {
192 10 : self.0.as_ref()
193 10 : }
194 : }
195 :
196 : impl std::ops::Deref for $name {
197 : type Target = str;
198 141 : fn deref(&self) -> &str {
199 141 : &*self.0
200 141 : }
201 : }
202 :
203 : impl<'de> serde::de::Deserialize<'de> for $name {
204 0 : fn deserialize<D: serde::de::Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
205 0 : <smol_str::SmolStr as serde::de::Deserialize<'de>>::deserialize(d).map(Self)
206 0 : }
207 : }
208 :
209 : impl serde::Serialize for $name {
210 0 : fn serialize<S: serde::Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
211 0 : self.0.serialize(s)
212 0 : }
213 : }
214 : };
215 : }
216 :
217 : const POOLER_SUFFIX: &str = "-pooler";
218 :
219 : impl EndpointId {
220 3 : fn normalize(&self) -> Self {
221 3 : if let Some(stripped) = self.as_ref().strip_suffix(POOLER_SUFFIX) {
222 0 : stripped.into()
223 : } else {
224 3 : self.clone()
225 : }
226 3 : }
227 :
228 0 : fn normalize_intern(&self) -> EndpointIdInt {
229 0 : if let Some(stripped) = self.as_ref().strip_suffix(POOLER_SUFFIX) {
230 0 : EndpointIdTag::get_interner().get_or_intern(stripped)
231 : } else {
232 0 : self.into()
233 : }
234 0 : }
235 : }
236 :
237 : // 90% of role name strings are 20 characters or less.
238 : smol_str_wrapper!(RoleName);
239 : // 50% of endpoint strings are 23 characters or less.
240 : smol_str_wrapper!(EndpointId);
241 : // 50% of branch strings are 23 characters or less.
242 : smol_str_wrapper!(BranchId);
243 : // 90% of project strings are 23 characters or less.
244 : smol_str_wrapper!(ProjectId);
245 :
246 : // will usually equal endpoint ID
247 : smol_str_wrapper!(EndpointCacheKey);
248 :
249 : smol_str_wrapper!(DbName);
250 :
251 : // postgres hostname, will likely be a port:ip addr
252 : smol_str_wrapper!(Host);
253 :
254 : // Endpoints are a bit tricky. Rare they might be branches or projects.
255 : impl EndpointId {
256 0 : pub(crate) fn is_endpoint(&self) -> bool {
257 0 : self.0.starts_with("ep-")
258 0 : }
259 0 : pub(crate) fn is_branch(&self) -> bool {
260 0 : self.0.starts_with("br-")
261 0 : }
262 : // pub(crate) fn is_project(&self) -> bool {
263 : // !self.is_endpoint() && !self.is_branch()
264 : // }
265 0 : pub(crate) fn as_branch(&self) -> BranchId {
266 0 : BranchId(self.0.clone())
267 0 : }
268 0 : pub(crate) fn as_project(&self) -> ProjectId {
269 0 : ProjectId(self.0.clone())
270 0 : }
271 : }
|