Skip to main content

natx_core/
lib.rs

1//! 数据库后端中立的 datasource 身份、受管所有权与事务裁决合同。
2//!
3//! 本 crate 不创建连接,也不依赖 SQLx 的数据库 feature。MySQL、PostgreSQL 与 SQLite driver crate
4//! 通过同一进程协调器发布 typed registry,确保同一 Application 只有一张名称与 driver catalog。
5//! 每个 datasource 独立选择编入的 driver;完整 catalog 开放前 getter 不发放资源,错 driver 拒绝。
6//! SQLite 文件 owner 与物理连接生命周期由对应 adapter 负责,本 crate 只裁决共享身份与准入。
7//! 连接观测按固定 datasource 与 purpose 区分 Pool acquire、事务槽等待和执行前拒绝;取消只收口
8//! 一次终态,Pool 状态为近似快照。等待日志与有界通知不能改变连接结果,不计作 Mapper 执行耗时。
9
10use std::collections::BTreeMap;
11use std::future::Future;
12use std::sync::atomic::{AtomicU64, AtomicU8, Ordering};
13use std::sync::{Arc, Mutex, OnceLock, Weak};
14
15/// 默认 datasource 的规范名称。
16pub const DEFAULT_DATASOURCE: &str = "default";
17
18pub mod observability;
19/// datasource qualifier 的最大 UTF-8 字节数。
20pub const MAX_DATASOURCE_NAME_BYTES: usize = 128;
21/// 单个受管 Application 可发布的 datasource 总数上限。
22pub const MAX_MANAGED_DATASOURCES: usize = 64;
23
24/// 业务作用:标识 datasource 使用的数据库协议与事务实现。
25#[derive(
26    Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, serde::Deserialize, serde::Serialize,
27)]
28#[serde(rename_all = "lowercase")]
29pub enum DatabaseDriver {
30    /// MySQL 或兼容协议。
31    MySql,
32    /// PostgreSQL 协议。
33    PostgreSql,
34    /// 本地 SQLite 文件数据库。
35    Sqlite,
36}
37
38/// 业务作用:声明当前编译产物实际包含的数据库后端,避免把可解析 driver 误当成已编入能力。
39#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
40pub struct DatabaseCapabilities(u8);
41
42impl DatabaseCapabilities {
43    const MYSQL: u8 = 1;
44    const POSTGRESQL: u8 = 1 << 1;
45    const SQLITE: u8 = 1 << 2;
46
47    /// 业务作用:构造不包含任何数据库后端的能力集合。
48    ///
49    /// 参数说明: 无。
50    ///
51    /// 返回:可继续通过 [`Self::with`] 组合的空集合。
52    pub const fn empty() -> Self {
53        Self(0)
54    }
55
56    /// 业务作用:把一个已经编入的 typed driver 加入能力集合。
57    ///
58    /// 参数说明:
59    /// - `driver`:是由对应 Cargo feature 实际编入的后端。
60    ///
61    /// 返回:包含原集合和指定 driver 的新集合。
62    pub const fn with(self, driver: DatabaseDriver) -> Self {
63        let flag = match driver {
64            DatabaseDriver::MySql => Self::MYSQL,
65            DatabaseDriver::PostgreSql => Self::POSTGRESQL,
66            DatabaseDriver::Sqlite => Self::SQLITE,
67        };
68        Self(self.0 | flag)
69    }
70
71    /// 业务作用:复验配置声明的 driver 是否已经编入当前运行产物。
72    ///
73    /// 参数说明:
74    /// - `driver`:是配置边界解析出的后端。
75    ///
76    /// 返回:对应 typed runtime 存在时返回真。
77    pub const fn contains(self, driver: DatabaseDriver) -> bool {
78        let flag = match driver {
79            DatabaseDriver::MySql => Self::MYSQL,
80            DatabaseDriver::PostgreSql => Self::POSTGRESQL,
81            DatabaseDriver::Sqlite => Self::SQLITE,
82        };
83        self.0 & flag != 0
84    }
85}
86
87impl std::fmt::Display for DatabaseDriver {
88    /// 业务作用:输出稳定、低基数的 driver 名称。
89    ///
90    /// 参数说明:
91    /// - `formatter`:是标准格式化目标。
92    ///
93    /// 返回:名称写入成功时返回 `Ok`,否则返回格式化错误。
94    fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
95        formatter.write_str(match self {
96            Self::MySql => "mysql",
97            Self::PostgreSql => "postgresql",
98            Self::Sqlite => "sqlite",
99        })
100    }
101}
102
103/// 业务作用:描述 datasource qualifier 在配置边界被拒绝的稳定原因。
104#[derive(Debug, Clone, Copy, PartialEq, Eq, thiserror::Error)]
105pub enum DatasourceNameError {
106    /// 名称为空。
107    #[error("datasource name cannot be empty")]
108    Empty,
109    /// 名称包含首尾空白。
110    #[error("datasource name cannot contain leading or trailing whitespace")]
111    SurroundingWhitespace,
112    /// 名称超长或包含不受支持的字符。
113    #[error("datasource name must use ASCII letters, digits, '.', '_' or '-' and stay within the byte limit")]
114    InvalidCharacters,
115}
116
117/// 业务作用:携带经过统一校验的 datasource 身份,使各 driver 不依赖临时字符串解释名称。
118#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
119pub struct DatasourceRef(Arc<str>);
120
121impl DatasourceRef {
122    /// 业务作用:以既有兼容签名校验并固定一个 datasource qualifier。
123    ///
124    /// 参数说明:
125    /// - `name`:是配置边界或业务计划给出的数据源名。
126    ///
127    /// 返回:名称符合有界 canonical 合同时返回拥有型引用;失败时在 anyhow 错误链保留具名原因。
128    pub fn new(name: impl AsRef<str>) -> anyhow::Result<Self> {
129        Self::try_new(name).map_err(anyhow::Error::new)
130    }
131
132    /// 业务作用:为 checked 配置与事务入口校验 datasource qualifier 并保留结构化失败分类。
133    ///
134    /// 参数说明:
135    /// - `name`:是配置边界或业务计划给出的数据源名。
136    ///
137    /// 返回:名称符合有界 canonical 合同时返回拥有型引用,否则返回 [`DatasourceNameError`]。
138    pub fn try_new(name: impl AsRef<str>) -> Result<Self, DatasourceNameError> {
139        let name = name.as_ref();
140        validate_datasource_name(name)?;
141        Ok(Self(Arc::from(name)))
142    }
143
144    /// 业务作用:返回默认 datasource 的规范化身份。
145    ///
146    /// 参数说明: 无。
147    ///
148    /// 返回:名称固定为 `default` 的拥有型引用。
149    pub fn default_ref() -> Self {
150        Self(Arc::from(DEFAULT_DATASOURCE))
151    }
152
153    /// 业务作用:读取 datasource 的规范化 qualifier。
154    ///
155    /// 参数说明: 无。
156    ///
157    /// 返回:与该引用同生命周期的名称切片。
158    pub fn as_str(&self) -> &str {
159        &self.0
160    }
161}
162
163impl Default for DatasourceRef {
164    /// 业务作用:为兼容无参入口选择默认 datasource。
165    ///
166    /// 参数说明: 无。
167    ///
168    /// 返回:默认 datasource 引用。
169    fn default() -> Self {
170        Self::default_ref()
171    }
172}
173
174impl AsRef<str> for DatasourceRef {
175    /// 业务作用:让事务与连接 API 消费已校验 datasource 身份。
176    ///
177    /// 参数说明: 无。
178    ///
179    /// 返回:规范化 datasource 名称。
180    fn as_ref(&self) -> &str {
181        self.as_str()
182    }
183}
184
185impl std::fmt::Display for DatasourceRef {
186    /// 业务作用:输出不含连接信息的 datasource qualifier。
187    ///
188    /// 参数说明:
189    /// - `formatter`:是标准格式化目标。
190    ///
191    /// 返回:名称写入成功时返回 `Ok`,否则返回格式化错误。
192    fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
193        formatter.write_str(self.as_str())
194    }
195}
196
197/// 业务作用:校验 datasource 名称可安全用于配置键、指标 label 与诊断字段。
198///
199/// 参数说明:
200/// - `name`:是待校验的 qualifier。
201///
202/// 返回:名称合法时返回 `Ok`,否则返回不包含输入内容的稳定分类。
203pub fn validate_datasource_name(name: &str) -> Result<(), DatasourceNameError> {
204    if name.is_empty() {
205        return Err(DatasourceNameError::Empty);
206    }
207    if name.trim() != name {
208        return Err(DatasourceNameError::SurroundingWhitespace);
209    }
210    if name.len() > MAX_DATASOURCE_NAME_BYTES
211        || !name
212            .bytes()
213            .all(|value| value.is_ascii_alphanumeric() || matches!(value, b'.' | b'_' | b'-'))
214    {
215        return Err(DatasourceNameError::InvalidCharacters);
216    }
217    Ok(())
218}
219
220/// 业务作用:承载两种数据库连接池共同使用的启动配置,不解释具体 URL scheme。
221#[derive(Clone, serde::Deserialize)]
222#[serde(deny_unknown_fields)]
223pub struct DataSourcePoolConfig {
224    /// 数据库连接串;driver 包装层负责校验 scheme。
225    pub url: String,
226    /// 连接池上限。
227    #[serde(default = "default_max_connections")]
228    pub max_connections: u32,
229    /// 连接池下限。
230    #[serde(default)]
231    pub min_connections: u32,
232    /// 从池中获取连接的等待上限,毫秒。
233    #[serde(default = "default_acquire_timeout_ms")]
234    pub acquire_timeout_ms: u64,
235    /// 建立单条连接的等待上限,毫秒。
236    #[serde(default = "default_connect_timeout_ms")]
237    pub connect_timeout_ms: u64,
238    /// 启动时是否先执行真实单连接探测。
239    #[serde(default = "default_probe_on_start")]
240    pub probe_on_start: bool,
241}
242
243impl std::fmt::Debug for DataSourcePoolConfig {
244    /// 业务作用:输出不含用户名和口令的池配置诊断视图。
245    ///
246    /// 参数说明:
247    /// - `formatter`:是标准格式化目标。
248    ///
249    /// 返回:脱敏字段写入成功时返回 `Ok`,否则返回格式化错误。
250    fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
251        formatter
252            .debug_struct("DataSourcePoolConfig")
253            .field("url", &redact_url(&self.url))
254            .field("max_connections", &self.max_connections)
255            .field("min_connections", &self.min_connections)
256            .field("acquire_timeout_ms", &self.acquire_timeout_ms)
257            .field("connect_timeout_ms", &self.connect_timeout_ms)
258            .field("probe_on_start", &self.probe_on_start)
259            .finish()
260    }
261}
262
263/// 业务作用:描述公共池参数在任何网络 I/O 前被拒绝的原因。
264#[derive(Debug, Clone, Copy, PartialEq, Eq, thiserror::Error)]
265pub enum PoolConfigError {
266    /// URL 为空。
267    #[error("datasource url cannot be empty")]
268    EmptyUrl,
269    /// 连接池上限为零。
270    #[error("datasource max_connections must be greater than zero")]
271    ZeroMaxConnections,
272    /// 连接池下限超过上限。
273    #[error("datasource min_connections cannot exceed max_connections")]
274    InvalidConnectionRange,
275    /// 获取连接超时为零。
276    #[error("datasource acquire_timeout_ms must be greater than zero")]
277    ZeroAcquireTimeout,
278    /// 建连超时为零。
279    #[error("datasource connect_timeout_ms must be greater than zero")]
280    ZeroConnectTimeout,
281}
282
283impl DataSourcePoolConfig {
284    /// 业务作用:校验与 driver 无关的池容量和超时合同。
285    ///
286    /// 参数说明: 无。
287    ///
288    /// 返回:公共配置可用于建池时返回 `Ok`;失败时不产生连接副作用。
289    pub fn validate_common(&self) -> Result<(), PoolConfigError> {
290        if self.url.trim().is_empty() {
291            return Err(PoolConfigError::EmptyUrl);
292        }
293        if self.max_connections == 0 {
294            return Err(PoolConfigError::ZeroMaxConnections);
295        }
296        if self.min_connections > self.max_connections {
297            return Err(PoolConfigError::InvalidConnectionRange);
298        }
299        if self.acquire_timeout_ms == 0 {
300            return Err(PoolConfigError::ZeroAcquireTimeout);
301        }
302        if self.connect_timeout_ms == 0 {
303            return Err(PoolConfigError::ZeroConnectTimeout);
304        }
305        Ok(())
306    }
307
308    /// 业务作用:返回可安全写入日志的 host、端口与 database 定位信息。
309    ///
310    /// 参数说明: 无。
311    ///
312    /// 返回:移除 scheme、userinfo、query 与 fragment 后的 endpoint;无法识别时返回固定占位符。
313    pub fn endpoint(&self) -> String {
314        redacted_endpoint(&self.url)
315    }
316}
317
318/// 业务作用:去掉 URL 中的 userinfo,同时保留 scheme 供 Debug 识别 driver。
319///
320/// 参数说明:
321/// - `url`:是可能包含凭据的数据库连接串。
322///
323/// 返回:不包含用户名和口令的字符串;scheme 或 endpoint 无法安全识别时返回固定占位符。
324pub fn redact_url(url: &str) -> String {
325    let Some((scheme, rest)) = url.split_once("://") else {
326        return "<redacted-url>".to_owned();
327    };
328    if scheme.is_empty()
329        || !scheme
330            .bytes()
331            .all(|value| value.is_ascii_alphanumeric() || matches!(value, b'+' | b'-' | b'.'))
332    {
333        return "<redacted-url>".to_owned();
334    }
335    let endpoint = redacted_endpoint(url);
336    if endpoint == "<unknown-endpoint>" {
337        return "<redacted-url>".to_owned();
338    }
339    let authority = rest.split(['/', '?', '#']).next().unwrap_or(rest);
340    if authority.contains('@') {
341        format!("{scheme}://***@{endpoint}")
342    } else {
343        format!("{scheme}://{endpoint}")
344    }
345}
346
347/// 业务作用:生成不包含 scheme、用户信息和连接参数的数据库 endpoint。
348///
349/// 参数说明:
350/// - `url`:是 driver 已校验或即将校验的连接串。
351///
352/// 返回:可用于脱敏诊断的 endpoint;格式不完整时返回固定占位符。
353pub fn redacted_endpoint(url: &str) -> String {
354    let Some((_, rest)) = url.split_once("://") else {
355        return "<unknown-endpoint>".to_owned();
356    };
357    let authority_and_path = rest.rsplit_once('@').map_or(rest, |(_, value)| value);
358    let endpoint = authority_and_path
359        .split(['?', '#'])
360        .next()
361        .unwrap_or(authority_and_path);
362    if endpoint.is_empty() {
363        "<unknown-endpoint>".to_owned()
364    } else {
365        endpoint.to_owned()
366    }
367}
368
369/// 业务作用:返回连接池上限的公共缺省值。
370///
371/// 参数说明: 无。
372///
373/// 返回:面向普通服务实例的连接数上限。
374fn default_max_connections() -> u32 {
375    10
376}
377
378/// 业务作用:返回获取连接等待上限的公共缺省值。
379///
380/// 参数说明: 无。
381///
382/// 返回:毫秒单位的有限等待预算。
383fn default_acquire_timeout_ms() -> u64 {
384    2_000
385}
386
387/// 业务作用:返回建立连接等待上限的公共缺省值。
388///
389/// 参数说明: 无。
390///
391/// 返回:毫秒单位的握手预算。
392fn default_connect_timeout_ms() -> u64 {
393    5_000
394}
395
396/// 业务作用:返回是否默认在启动期探测真实连接。
397///
398/// 参数说明: 无。
399///
400/// 返回:固定为真,使地址、凭据和 database 错误在启动期暴露。
401fn default_probe_on_start() -> bool {
402    true
403}
404
405static NEXT_OWNER_ID: AtomicU64 = AtomicU64::new(1);
406
407#[derive(Debug)]
408/// 业务作用:为单个 Application 的数据库 registry 所有权提供不可由数值相等伪造的 Arc 身份。
409struct OwnerIdentity {
410    id: u64,
411}
412
413/// 业务作用:标识唯一 Application 对 catalog 与 typed registry 的共同所有权。
414#[derive(Clone)]
415pub struct ManagedRegistryOwner(Arc<OwnerIdentity>);
416
417impl ManagedRegistryOwner {
418    /// 业务作用:为一次 Application 数据库启动创建不可伪造的进程内所有权身份。
419    ///
420    /// 参数说明: 无。
421    ///
422    /// 返回:可安全 clone、按 Arc 身份复验的 owner。
423    pub fn new() -> Self {
424        Self(Arc::new(OwnerIdentity {
425            id: NEXT_OWNER_ID.fetch_add(1, Ordering::Relaxed),
426        }))
427    }
428
429    /// 业务作用:比较两个 owner 是否代表同一次 Application 启动。
430    ///
431    /// 参数说明:
432    /// - `other`:是待复验的 owner。
433    ///
434    /// 返回:底层身份相同时返回真。
435    pub fn ptr_eq(&self, other: &Self) -> bool {
436        Arc::ptr_eq(&self.0, &other.0)
437    }
438
439    /// 业务作用:返回不包含资源信息的进程内诊断编号。
440    ///
441    /// 参数说明: 无。
442    ///
443    /// 返回:本进程单调分配的 owner 编号,不作为跨进程协议值。
444    pub fn diagnostic_id(&self) -> u64 {
445        self.0.id
446    }
447
448    /// 业务作用:把 owner 降级为不延长 Application 生命周期的进程模式身份。
449    ///
450    /// 参数说明: 无。
451    ///
452    /// 返回:owner 最后一个强引用释放后无法升级的弱身份。
453    fn downgrade(&self) -> Weak<OwnerIdentity> {
454        Arc::downgrade(&self.0)
455    }
456}
457
458impl Default for ManagedRegistryOwner {
459    /// 业务作用:兼容需要 Default 构造的启动 staging,仍创建唯一 owner。
460    ///
461    /// 参数说明: 无。
462    ///
463    /// 返回:新的独立 owner。
464    fn default() -> Self {
465        Self::new()
466    }
467}
468
469impl std::fmt::Debug for ManagedRegistryOwner {
470    /// 业务作用:输出不包含连接资源的 owner 诊断视图。
471    ///
472    /// 参数说明:
473    /// - `formatter`:是标准格式化目标。
474    ///
475    /// 返回:诊断编号写入成功时返回 `Ok`。
476    fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
477        formatter
478            .debug_tuple("ManagedRegistryOwner")
479            .field(&self.diagnostic_id())
480            .finish()
481    }
482}
483
484/// 业务作用:区分常规配置建池与 UserHook 延后 default 引导。
485#[derive(Debug, Clone, Copy, PartialEq, Eq)]
486pub enum BootstrapKind {
487    /// Application 根据冻结配置建立全部 datasource。
488    Configured,
489    /// UserHook 只安装一个 default,Prepare 再接管。
490    DeferredDefault,
491}
492
493/// 业务作用:证明调用方持有当前 Bootstrapping owner,可执行关闭态安装与状态迁移。
494#[derive(Clone, Debug)]
495pub struct ManagedInstallationToken {
496    owner: ManagedRegistryOwner,
497    kind: BootstrapKind,
498}
499
500impl ManagedInstallationToken {
501    /// 业务作用:读取 token 绑定的 Application owner。
502    ///
503    /// 参数说明: 无。
504    ///
505    /// 返回:只读 owner 引用,供 typed registry 绑定同一身份。
506    pub fn owner(&self) -> &ManagedRegistryOwner {
507        &self.owner
508    }
509
510    /// 业务作用:读取本次启动采用的引导路径。
511    ///
512    /// 参数说明: 无。
513    ///
514    /// 返回:配置建池或延后 default 类型。
515    pub fn kind(&self) -> BootstrapKind {
516        self.kind
517    }
518}
519
520/// 业务作用:作为单个 Application 的冻结 datasource 名称与 driver 权威。
521pub struct DataSourceCatalog {
522    owner: ManagedRegistryOwner,
523    entries: BTreeMap<DatasourceRef, DatabaseDriver>,
524    lifecycle: AtomicU8,
525}
526
527const CATALOG_STAGING: u8 = 0;
528const CATALOG_OPEN: u8 = 1;
529const CATALOG_STOPPED: u8 = 2;
530
531impl DataSourceCatalog {
532    /// 业务作用:构造尚未对 getter 开放的冻结 catalog。
533    ///
534    /// 参数说明:
535    /// - `owner`:本次 Application 的共同 owner。
536    /// - `entries`:datasource qualifier 与 driver 的完整集合。
537    ///
538    /// 返回:名称合法、不重复、非空且数量有界时返回关闭态 catalog;失败不发布部分表。
539    pub fn try_new(
540        owner: ManagedRegistryOwner,
541        entries: impl IntoIterator<Item = (String, DatabaseDriver)>,
542    ) -> Result<Self, CatalogBuildError> {
543        let mut catalog = BTreeMap::new();
544        for (name, driver) in entries {
545            if catalog.len() >= MAX_MANAGED_DATASOURCES {
546                return Err(CatalogBuildError::TooManyDatasources);
547            }
548            let reference = DatasourceRef::try_new(name).map_err(CatalogBuildError::InvalidName)?;
549            if catalog.insert(reference.clone(), driver).is_some() {
550                return Err(CatalogBuildError::Duplicate(reference));
551            }
552        }
553        if catalog.is_empty() {
554            return Err(CatalogBuildError::Empty);
555        }
556        Ok(Self {
557            owner,
558            entries: catalog,
559            lifecycle: AtomicU8::new(CATALOG_STAGING),
560        })
561    }
562
563    /// 业务作用:读取 catalog 绑定的 Application owner。
564    ///
565    /// 参数说明: 无。
566    ///
567    /// 返回:共同 owner 的只读引用。
568    pub fn owner(&self) -> &ManagedRegistryOwner {
569        &self.owner
570    }
571
572    /// 业务作用:返回冻结 catalog 的 datasource 数量。
573    ///
574    /// 参数说明: 无。
575    ///
576    /// 返回:跨 driver 合计的条目数。
577    pub fn len(&self) -> usize {
578        self.entries.len()
579    }
580
581    /// 业务作用:判断 catalog 是否没有 datasource。
582    ///
583    /// 参数说明: 无。
584    ///
585    /// 返回:构造成功后固定为假;该入口供通用容器检查使用。
586    pub fn is_empty(&self) -> bool {
587        self.entries.is_empty()
588    }
589
590    /// 业务作用:复制冻结后的 datasource 与 driver 表,供资源登记和观测快照使用。
591    ///
592    /// 参数说明: 无。
593    ///
594    /// 返回:按 datasource 名排序的拥有型条目。
595    pub fn entries(&self) -> Vec<(DatasourceRef, DatabaseDriver)> {
596        self.entries
597            .iter()
598            .map(|(reference, driver)| (reference.clone(), *driver))
599            .collect()
600    }
601
602    /// 业务作用:在 catalog 已开放时解析名称并复验调用方期待的 driver。
603    ///
604    /// 参数说明:
605    /// - `datasource`:待解析名称。
606    /// - `expected`:typed getter 对应的 driver。
607    ///
608    /// 返回:名称和 driver 同时匹配时返回规范引用;关闭、缺失或错配时返回结构化错误。
609    pub fn resolve(
610        &self,
611        datasource: &str,
612        expected: DatabaseDriver,
613    ) -> Result<DatasourceRef, DataSourceLookupError> {
614        match self.lifecycle.load(Ordering::Acquire) {
615            CATALOG_OPEN => {}
616            CATALOG_STOPPED => return Err(DataSourceLookupError::Stopped),
617            _ => return Err(DataSourceLookupError::RegistryUnavailable),
618        }
619        let reference =
620            DatasourceRef::new(datasource).map_err(|_| DataSourceLookupError::InvalidName)?;
621        let actual = self.entries.get(&reference).copied().ok_or_else(|| {
622            DataSourceLookupError::NotFound {
623                datasource: reference.clone(),
624            }
625        })?;
626        if actual != expected {
627            return Err(DataSourceLookupError::DriverMismatch {
628                datasource: reference,
629                expected,
630                actual,
631            });
632        }
633        Ok(reference)
634    }
635
636    /// 业务作用:在全部 typed registry 与资源容器提交后开放 catalog 查询。
637    ///
638    /// 参数说明: 无。
639    ///
640    /// 返回:无;Release 写入保证后续 getter 看见完整冻结条目。
641    fn open(&self) {
642        self.lifecycle.store(CATALOG_OPEN, Ordering::Release);
643    }
644
645    /// 业务作用:在关闭连接池前永久封口 catalog,阻止停机期发放新资源。
646    ///
647    /// 参数说明: 无。
648    ///
649    /// 返回:无;后续查询得到 stopped 分类。
650    fn stop_accepting(&self) {
651        self.lifecycle.store(CATALOG_STOPPED, Ordering::Release);
652    }
653}
654
655/// 业务作用:描述冻结 catalog 构造失败的无连接副作用原因。
656#[derive(Debug, thiserror::Error)]
657pub enum CatalogBuildError {
658    /// 没有 datasource。
659    #[error("managed datasource catalog cannot be empty")]
660    Empty,
661    /// 数量超过受管上限。
662    #[error("managed datasource count exceeds the supported limit")]
663    TooManyDatasources,
664    /// 名称非法。
665    #[error("invalid datasource name")]
666    InvalidName(#[source] DatasourceNameError),
667    /// 名称重复。
668    #[error("datasource `{0}` is configured more than once")]
669    Duplicate(DatasourceRef),
670}
671
672/// 业务作用:为 typed getter 提供稳定的 datasource 查找失败分类。
673#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]
674pub enum DataSourceLookupError {
675    /// 名称格式非法。
676    #[error("invalid datasource name")]
677    InvalidName,
678    /// catalog 尚未安装、尚未开放或已失去受管身份。
679    #[error("datasource registry is unavailable")]
680    RegistryUnavailable,
681    /// catalog 已完成封口,旧 Application 不再发放连接。
682    #[error("datasource registry is stopped")]
683    Stopped,
684    /// 名称不在当前 Application catalog。
685    #[error("datasource `{datasource}` is not managed by this application")]
686    NotFound {
687        /// 已校验的 datasource 名称。
688        datasource: DatasourceRef,
689    },
690    /// 名称存在但属于另一数据库 driver。
691    #[error("datasource `{datasource}` uses {actual}, not {expected}")]
692    DriverMismatch {
693        /// 已校验的 datasource 名称。
694        datasource: DatasourceRef,
695        /// typed getter 期待的 driver。
696        expected: DatabaseDriver,
697        /// catalog 中的实际 driver。
698        actual: DatabaseDriver,
699    },
700}
701
702/// 业务作用:对显式事务裁决的全部失败阶段进行封闭分类。
703#[must_use]
704#[derive(Debug, Clone, PartialEq, Eq)]
705pub enum TxDecision<T, E> {
706    /// 当前执行已得到允许提交的领域结果。
707    Commit(T),
708    /// 当前执行没有可提交结果,必须回滚。
709    Rollback(E),
710}
711
712/// 业务作用:保留物理回滚失败之前的原始裁决来源。
713#[derive(Debug)]
714pub enum TxRollbackCause<E> {
715    /// 最外层事务体显式要求回滚。
716    Decision(E),
717    /// 内层事务要求 rollback-only,但外层吞掉了原始错误。
718    RollbackOnly {
719        /// 首次置位时保存的脱敏原因。
720        reason: String,
721    },
722}
723
724/// 业务作用:封闭提交、回滚和基础设施失败分类,供消息 ACK 与重试策略裁决。
725#[derive(Debug)]
726pub enum TxRunError<E> {
727    /// 业务要求回滚,且数据库确认回滚完成。
728    Rollback(E),
729    /// 内层回滚要求被外层吞掉,最外层已确认整体回滚。
730    RollbackOnly {
731        /// 首次置位 rollback-only 时保存的脱敏原因。
732        reason: String,
733    },
734    /// 数据库明确拒绝 COMMIT。
735    CommitRejected {
736        /// 稳定、脱敏的失败分类。
737        reason: String,
738    },
739    /// COMMIT 后连接或协议状态不确定。
740    CommitUncertain {
741        /// 稳定、脱敏的失败分类。
742        reason: String,
743    },
744    /// 物理回滚失败。
745    RollbackFailed {
746        /// 触发回滚的原始裁决。
747        cause: TxRollbackCause<E>,
748        /// 稳定、脱敏的基础设施分类。
749        reason: String,
750    },
751    /// 在事务开始前或内核执行中发生基础设施错误。
752    Infrastructure {
753        /// 稳定、脱敏的失败分类。
754        reason: String,
755    },
756}
757
758/// 业务作用:让加法事务入口分别保留 datasource 查找与事务执行失败,避免调用方解析文本。
759#[derive(Debug)]
760pub enum TxEntryError<E> {
761    /// 事务开始前的 datasource 名称、状态或 driver 校验失败。
762    Lookup(DataSourceLookupError),
763    /// 已进入对应 typed runtime 后的事务裁决失败。
764    Run(TxRunError<E>),
765}
766
767impl<E: std::fmt::Display> std::fmt::Display for TxEntryError<E> {
768    /// 业务作用:输出 checked 事务入口的脱敏失败阶段和稳定原因。
769    ///
770    /// 参数说明:
771    /// - `formatter`:是标准格式化目标。
772    ///
773    /// 返回:分类写入成功时返回 `Ok`,否则返回格式化错误。
774    fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
775        match self {
776            Self::Lookup(error) => {
777                write!(formatter, "transaction datasource lookup failed: {error}")
778            }
779            Self::Run(error) => std::fmt::Display::fmt(error, formatter),
780        }
781    }
782}
783
784impl<E> std::error::Error for TxEntryError<E> where E: std::fmt::Debug + std::fmt::Display {}
785
786/// 业务作用:描述数据库对 COMMIT 的可确认结果,供 driver 映射协议级错误。
787#[derive(Debug, Clone, Copy, PartialEq, Eq)]
788pub enum CommitOutcome {
789    /// 数据库明确确认提交完成。
790    Committed,
791    /// 数据库返回明确拒绝,事务没有获得成功确认。
792    Rejected,
793    /// 请求发出后连接或协议中断,无法确认服务端最终结果。
794    OutcomeUnknown,
795}
796
797impl<E: std::fmt::Display> std::fmt::Display for TxRunError<E> {
798    /// 业务作用:输出不含 SQL、连接串和 payload 的事务失败分类。
799    ///
800    /// 参数说明:
801    /// - `formatter`:是标准格式化目标。
802    ///
803    /// 返回:分类写入成功时返回 `Ok`,否则返回格式化错误。
804    fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
805        match self {
806            Self::Rollback(error) => write!(formatter, "transaction rolled back: {error}"),
807            Self::RollbackOnly {
808                reason,
809            } => {
810                write!(formatter, "transaction was rollback-only: {reason}")
811            }
812            Self::CommitRejected {
813                reason,
814            } => write!(formatter, "commit rejected: {reason}"),
815            Self::CommitUncertain {
816                reason,
817            } => write!(formatter, "commit uncertain: {reason}"),
818            Self::RollbackFailed {
819                reason,
820                ..
821            } => write!(formatter, "rollback failed: {reason}"),
822            Self::Infrastructure {
823                reason,
824            } => {
825                write!(formatter, "transaction infrastructure failed: {reason}")
826            }
827        }
828    }
829}
830
831impl<E> std::error::Error for TxRunError<E> where E: std::fmt::Debug + std::fmt::Display {}
832
833/// 业务作用:描述 driver task-local 的跨后端嵌套拒绝。
834#[derive(Debug, Clone, Copy, PartialEq, Eq, thiserror::Error)]
835#[error("ambient transaction driver mismatch: active={active}, requested={requested}")]
836pub struct DriverScopeError {
837    /// 当前任务已绑定的 driver。
838    pub active: DatabaseDriver,
839    /// 本次调用请求的 driver。
840    pub requested: DatabaseDriver,
841}
842
843tokio::task_local! {
844    static ACTIVE_DRIVER: DatabaseDriver;
845}
846
847/// 业务作用:读取当前任务的 ambient transaction driver 哨兵。
848///
849/// 参数说明: 无。
850///
851/// 返回:事务体内返回对应 driver;普通任务与新 spawn 的任务返回 `None`。
852pub fn current_driver() -> Option<DatabaseDriver> {
853    ACTIVE_DRIVER.try_with(|driver| *driver).ok()
854}
855
856/// 业务作用:在执行 SQL 或进入 driver 事务前拒绝跨 driver 复用。
857///
858/// 参数说明:
859/// - `requested`:是本次 typed 入口对应的 driver。
860///
861/// 返回:当前无哨兵或 driver 一致时成功;错配时返回两侧身份。
862pub fn ensure_driver(requested: DatabaseDriver) -> Result<(), DriverScopeError> {
863    match current_driver() {
864        Some(active) if active != requested => Err(DriverScopeError {
865            active,
866            requested,
867        }),
868        _ => Ok(()),
869    }
870}
871
872/// 业务作用:仅在事务业务体执行期间发布 driver 哨兵,阻止嵌套进入另一后端。
873///
874/// 参数说明:
875/// - `driver`:本地事务使用的数据库后端。
876/// - `future`:需要在该后端事务上下文中执行的业务 future。
877///
878/// 返回:无外层 driver 或与外层一致时返回业务输出;错配时不执行 future。
879pub async fn scope_driver<F>(
880    driver: DatabaseDriver,
881    future: F,
882) -> Result<F::Output, DriverScopeError>
883where
884    F: Future,
885{
886    match current_driver() {
887        Some(active) if active != driver => Err(DriverScopeError {
888            active,
889            requested: driver,
890        }),
891        Some(_) => Ok(future.await),
892        None => Ok(ACTIVE_DRIVER.scope(driver, future).await),
893    }
894}
895
896/// 业务作用:对进程级 datasource 模式变化给出稳定拒绝原因。
897#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]
898pub enum RegistryCoordinationError {
899    /// 另一 driver 已占用 standalone 模式。
900    #[error("standalone datasource driver conflicts with the active driver")]
901    StandaloneDriverConflict,
902    /// 受管或引导模式拒绝普通 standalone 注册。
903    #[error("standalone datasource registration conflicts with managed application state")]
904    ManagedModeConflict,
905    /// 延后引导只允许 default。
906    #[error("deferred datasource bootstrap accepts only the default datasource")]
907    DeferredOnlyDefault,
908    /// 延后引导已记录另一 driver。
909    #[error("deferred datasource bootstrap already uses another driver")]
910    DeferredDriverConflict,
911    /// 当前模式不能开始新的 Application 引导。
912    #[error("datasource registry is already occupied")]
913    RegistryOccupied,
914    /// owner token 不属于当前启动。
915    #[error("managed registry owner token does not match the active bootstrap")]
916    OwnerMismatch,
917    /// catalog 与 typed registry 没有使用同一 owner。
918    #[error("datasource catalog owner does not match the installation token")]
919    CatalogOwnerMismatch,
920    /// catalog 实例与已发布实例不同。
921    #[error("datasource catalog identity does not match the active managed catalog")]
922    CatalogIdentityMismatch,
923    /// 延后引导没有安装对应 driver 的 default。
924    #[error("deferred datasource bootstrap did not install the expected default driver")]
925    DeferredDriverMissing,
926    /// 清理前仍有延后 standalone 资源。
927    #[error("deferred datasource resources must be removed before bootstrap cleanup")]
928    DeferredResourcesRemain,
929    /// 无 token 的公开 adopt 不能越过 Bootstrapping。
930    #[error("public standalone adopt is unavailable during application bootstrap")]
931    PublicAdoptDuringBootstrap,
932    /// 模式已失去 owner,但仍记录待清理资源。
933    #[error("orphaned deferred datasource resources require explicit cleanup")]
934    OrphanedDeferredResources,
935    /// catalog 不符合延后 default 的单 driver 合同。
936    #[error("deferred datasource catalog must contain only the installed default driver")]
937    InvalidDeferredCatalog,
938}
939
940#[derive(Debug)]
941enum RegistryMode {
942    Empty,
943    Standalone(DatabaseDriver),
944    Bootstrapping {
945        owner: Weak<OwnerIdentity>,
946        kind: BootstrapKind,
947        deferred_driver: Option<DatabaseDriver>,
948    },
949    Managed {
950        owner: Weak<OwnerIdentity>,
951        catalog: Weak<DataSourceCatalog>,
952    },
953}
954
955#[derive(Debug)]
956/// 业务作用:保存进程级 datasource 安装模式与当前 owner 弱引用,线性化独立和受管入口。
957struct RegistryState {
958    mode: RegistryMode,
959}
960
961impl Default for RegistryState {
962    /// 业务作用:初始化尚无任何 datasource 权威的进程协调状态。
963    ///
964    /// 参数说明: 无。
965    ///
966    /// 返回:模式为 Empty 的协调器内部状态。
967    fn default() -> Self {
968        Self {
969            mode: RegistryMode::Empty,
970        }
971    }
972}
973
974static REGISTRY_STATE: OnceLock<Mutex<RegistryState>> = OnceLock::new();
975
976/// 业务作用:暴露进程 datasource 模式的低基数诊断快照。
977#[derive(Debug, Clone, Copy, PartialEq, Eq)]
978pub enum RegistryModeSnapshot {
979    /// 没有 datasource 权威。
980    Empty,
981    /// standalone driver 已占用进程入口。
982    Standalone(DatabaseDriver),
983    /// Application 正在构造受管资源。
984    Bootstrapping {
985        /// 启动路径。
986        kind: BootstrapKind,
987        /// UserHook 已安装的 default driver。
988        deferred_driver: Option<DatabaseDriver>,
989    },
990    /// catalog 已安装,可能仍处于关闭态。
991    Managed,
992    /// owner 已失效但 driver 资源尚待精确清理。
993    OrphanedDeferred(DatabaseDriver),
994}
995
996/// 业务作用:在唯一协调锁内组合 core 模式与 driver typed registry 的状态变化。
997///
998/// 参数说明:
999/// - `operation`:只获取当前 driver registry 锁并遵守锁顺序的同步协调操作。
1000///
1001/// 返回:先在锁中 sanitize 协调状态,再原样返回闭包结果;锁 poison 时取回内部状态。闭包在持锁期间运行,须保持 core 到 driver 的锁顺序且不得重入本函数。
1002#[doc(hidden)]
1003pub fn coordinate<T>(operation: impl FnOnce(&mut RegistryCoordinator<'_>) -> T) -> T {
1004    let mut state = REGISTRY_STATE
1005        .get_or_init(|| Mutex::new(RegistryState::default()))
1006        .lock()
1007        .unwrap_or_else(|error| error.into_inner());
1008    let mut coordinator = RegistryCoordinator {
1009        state: &mut state,
1010    };
1011    coordinator.sanitize();
1012    operation(&mut coordinator)
1013}
1014
1015/// 业务作用:在唯一协调锁内执行受管模式迁移,供 typed driver crate 原子组合本地资源变化。
1016#[doc(hidden)]
1017pub struct RegistryCoordinator<'a> {
1018    state: &'a mut RegistryState,
1019}
1020
1021impl RegistryCoordinator<'_> {
1022    /// 业务作用:清除不再持有资源的失效弱 owner,使同一进程能够启动新的 Application。
1023    ///
1024    /// 参数说明: 无。
1025    ///
1026    /// 返回:无;仍记录 deferred pool 时保留模式并要求精确清理。
1027    fn sanitize(&mut self) {
1028        match &self.state.mode {
1029            RegistryMode::Bootstrapping {
1030                owner,
1031                deferred_driver: None,
1032                ..
1033            } if owner.upgrade().is_none() => {
1034                self.state.mode = RegistryMode::Empty;
1035            }
1036            RegistryMode::Managed {
1037                owner,
1038                catalog,
1039            } if owner.upgrade().is_none() && catalog.upgrade().is_none() => {
1040                self.state.mode = RegistryMode::Empty;
1041            }
1042            _ => {}
1043        }
1044    }
1045
1046    /// 业务作用:登记一个 typed standalone datasource,并阻止跨 driver 或受管模式并存。
1047    ///
1048    /// 参数说明:
1049    /// - `driver`:执行登记的 typed driver。
1050    /// - `datasource`:即将写入 driver 本地表的名称。
1051    ///
1052    /// 返回:当前模式允许本地原子写入时成功;失败时调用方不得修改 pool 表。
1053    pub fn register_standalone(
1054        &mut self,
1055        driver: DatabaseDriver,
1056        datasource: &str,
1057    ) -> Result<(), RegistryCoordinationError> {
1058        match &mut self.state.mode {
1059            RegistryMode::Empty => {
1060                self.state.mode = RegistryMode::Standalone(driver);
1061                Ok(())
1062            }
1063            RegistryMode::Standalone(active) if *active == driver => Ok(()),
1064            RegistryMode::Standalone(_) => Err(RegistryCoordinationError::StandaloneDriverConflict),
1065            RegistryMode::Bootstrapping {
1066                owner,
1067                kind: BootstrapKind::DeferredDefault,
1068                deferred_driver,
1069            } => {
1070                if owner.upgrade().is_none() && deferred_driver.is_some() {
1071                    return Err(RegistryCoordinationError::OrphanedDeferredResources);
1072                }
1073                if datasource != DEFAULT_DATASOURCE {
1074                    return Err(RegistryCoordinationError::DeferredOnlyDefault);
1075                }
1076                match deferred_driver {
1077                    Some(active) if *active != driver => {
1078                        Err(RegistryCoordinationError::DeferredDriverConflict)
1079                    }
1080                    Some(_) => Ok(()),
1081                    slot @ None => {
1082                        *slot = Some(driver);
1083                        Ok(())
1084                    }
1085                }
1086            }
1087            RegistryMode::Bootstrapping {
1088                ..
1089            }
1090            | RegistryMode::Managed {
1091                ..
1092            } => Err(RegistryCoordinationError::ManagedModeConflict),
1093        }
1094    }
1095
1096    /// 业务作用:在 driver 已确认本地 standalone 表为空后释放进程模式。
1097    ///
1098    /// 参数说明:
1099    /// - `driver`:是刚完成精确清理的 typed driver。
1100    ///
1101    /// 返回:模式属于该 driver 时成功;另一 driver 或受管状态返回冲突。
1102    pub fn release_standalone(
1103        &mut self,
1104        driver: DatabaseDriver,
1105    ) -> Result<(), RegistryCoordinationError> {
1106        match &mut self.state.mode {
1107            RegistryMode::Standalone(active) if *active == driver => {
1108                self.state.mode = RegistryMode::Empty;
1109                Ok(())
1110            }
1111            RegistryMode::Bootstrapping {
1112                owner,
1113                kind: BootstrapKind::DeferredDefault,
1114                deferred_driver: Some(active),
1115            } if *active == driver => {
1116                let owner_alive = owner.upgrade().is_some();
1117                if owner_alive {
1118                    if let RegistryMode::Bootstrapping {
1119                        deferred_driver,
1120                        ..
1121                    } = &mut self.state.mode
1122                    {
1123                        *deferred_driver = None;
1124                    }
1125                } else {
1126                    self.state.mode = RegistryMode::Empty;
1127                }
1128                Ok(())
1129            }
1130            RegistryMode::Empty => Ok(()),
1131            _ => Err(RegistryCoordinationError::ManagedModeConflict),
1132        }
1133    }
1134
1135    /// 业务作用:开始一次配置建池或延后 default 的受管启动。
1136    ///
1137    /// 参数说明:
1138    /// - `owner`:本次 Application 唯一 owner。
1139    /// - `kind`:启动路径类型。
1140    ///
1141    /// 返回:进程入口为空时返回 owner token;已有资源时不改变模式。
1142    pub fn begin_bootstrap(
1143        &mut self,
1144        owner: &ManagedRegistryOwner,
1145        kind: BootstrapKind,
1146    ) -> Result<ManagedInstallationToken, RegistryCoordinationError> {
1147        if !matches!(self.state.mode, RegistryMode::Empty) {
1148            return Err(RegistryCoordinationError::RegistryOccupied);
1149        }
1150        self.state.mode = RegistryMode::Bootstrapping {
1151            owner: owner.downgrade(),
1152            kind,
1153            deferred_driver: None,
1154        };
1155        Ok(ManagedInstallationToken {
1156            owner: owner.clone(),
1157            kind,
1158        })
1159    }
1160
1161    /// 业务作用:把普通 standalone 转入旧公开 adopt 使用的受管安装窗口。
1162    ///
1163    /// 参数说明:
1164    /// - `owner`:旧入口内部新建的 owner。
1165    /// - `driver`:必须与当前 standalone driver 一致。
1166    ///
1167    /// 返回:普通 standalone 时返回 token;Bootstrapping 明确拒绝无 token 越权接管。
1168    pub fn begin_legacy_adopt(
1169        &mut self,
1170        owner: &ManagedRegistryOwner,
1171        driver: DatabaseDriver,
1172    ) -> Result<ManagedInstallationToken, RegistryCoordinationError> {
1173        match &self.state.mode {
1174            RegistryMode::Standalone(active) if *active == driver => {
1175                self.state.mode = RegistryMode::Bootstrapping {
1176                    owner: owner.downgrade(),
1177                    kind: BootstrapKind::Configured,
1178                    deferred_driver: None,
1179                };
1180                Ok(ManagedInstallationToken {
1181                    owner: owner.clone(),
1182                    kind: BootstrapKind::Configured,
1183                })
1184            }
1185            RegistryMode::Bootstrapping {
1186                ..
1187            } => Err(RegistryCoordinationError::PublicAdoptDuringBootstrap),
1188            _ => Err(RegistryCoordinationError::RegistryOccupied),
1189        }
1190    }
1191
1192    /// 业务作用:旧 adopt 发布失败时恢复调用前的 standalone 模式。
1193    ///
1194    /// 参数说明:
1195    /// - `token`:旧 adopt 创建的安装 token。
1196    /// - `driver`:恢复后的 standalone driver。
1197    ///
1198    /// 返回:owner 仍匹配时恢复;状态已被其它 owner 替换时拒绝。
1199    pub fn restore_legacy_standalone(
1200        &mut self,
1201        token: &ManagedInstallationToken,
1202        driver: DatabaseDriver,
1203    ) -> Result<(), RegistryCoordinationError> {
1204        self.verify_bootstrap_owner(token)?;
1205        self.state.mode = RegistryMode::Standalone(driver);
1206        Ok(())
1207    }
1208
1209    /// 业务作用:复验延后 default 已由同一 owner 安装指定 driver,允许关闭态接管。
1210    ///
1211    /// 参数说明:
1212    /// - `token`:Application 在 Start 领取的 token。
1213    /// - `driver`:typed adopt 对应的 driver。
1214    ///
1215    /// 返回:owner、kind 与 deferred driver 全部匹配时成功。
1216    pub fn verify_deferred_adopt(
1217        &mut self,
1218        token: &ManagedInstallationToken,
1219        driver: DatabaseDriver,
1220    ) -> Result<(), RegistryCoordinationError> {
1221        self.verify_bootstrap_owner(token)?;
1222        match &self.state.mode {
1223            RegistryMode::Bootstrapping {
1224                kind: BootstrapKind::DeferredDefault,
1225                deferred_driver: Some(active),
1226                ..
1227            } if *active == driver => Ok(()),
1228            _ => Err(RegistryCoordinationError::DeferredDriverMissing),
1229        }
1230    }
1231
1232    /// 业务作用:复验 typed registry 安装者持有当前 Bootstrapping owner token。
1233    ///
1234    /// 参数说明:
1235    /// - `token`:是 driver crate 收到的安装凭据。
1236    ///
1237    /// 返回:owner 与启动类型同时匹配时成功;错配时不得修改 driver 本地槽。
1238    pub fn verify_installation_token(
1239        &self,
1240        token: &ManagedInstallationToken,
1241    ) -> Result<(), RegistryCoordinationError> {
1242        self.verify_bootstrap_owner(token)
1243    }
1244
1245    /// 业务作用:把关闭态 catalog 安装为进程唯一受管权威,但尚不开放 getter。
1246    ///
1247    /// 参数说明:
1248    /// - `token`:当前 Application token。
1249    /// - `catalog`:已冻结且 owner 相同的完整 catalog。
1250    ///
1251    /// 返回:模式和 owner 匹配时转入 Managed;失败时 catalog 保持关闭。
1252    pub fn install_catalog(
1253        &mut self,
1254        token: &ManagedInstallationToken,
1255        catalog: &Arc<DataSourceCatalog>,
1256    ) -> Result<(), RegistryCoordinationError> {
1257        self.verify_bootstrap_owner(token)?;
1258        if !catalog.owner().ptr_eq(token.owner()) {
1259            return Err(RegistryCoordinationError::CatalogOwnerMismatch);
1260        }
1261        if let RegistryMode::Bootstrapping {
1262            kind: BootstrapKind::DeferredDefault,
1263            deferred_driver: Some(driver),
1264            ..
1265        } = &self.state.mode
1266        {
1267            let entries = catalog.entries();
1268            if entries.len() != 1
1269                || entries[0].0.as_str() != DEFAULT_DATASOURCE
1270                || entries[0].1 != *driver
1271            {
1272                return Err(RegistryCoordinationError::InvalidDeferredCatalog);
1273            }
1274        }
1275        self.state.mode = RegistryMode::Managed {
1276            owner: token.owner.downgrade(),
1277            catalog: Arc::downgrade(catalog),
1278        };
1279        Ok(())
1280    }
1281
1282    /// 业务作用:在 typed registry 与 Application 资源表全部提交后开放唯一 catalog。
1283    ///
1284    /// 参数说明:
1285    /// - `token`:当前 Application token。
1286    /// - `catalog`:必须是已安装的同一 Arc 实例。
1287    ///
1288    /// 返回:身份复验通过时开放 getter;错配时保持关闭。
1289    pub fn open_catalog(
1290        &mut self,
1291        token: &ManagedInstallationToken,
1292        catalog: &Arc<DataSourceCatalog>,
1293    ) -> Result<(), RegistryCoordinationError> {
1294        match &self.state.mode {
1295            RegistryMode::Managed {
1296                owner,
1297                catalog: active,
1298            } => {
1299                let Some(active_owner) = owner.upgrade() else {
1300                    return Err(RegistryCoordinationError::OwnerMismatch);
1301                };
1302                if !Arc::ptr_eq(&active_owner, &token.owner.0) {
1303                    return Err(RegistryCoordinationError::OwnerMismatch);
1304                }
1305                let Some(active_catalog) = active.upgrade() else {
1306                    return Err(RegistryCoordinationError::CatalogIdentityMismatch);
1307                };
1308                if !Arc::ptr_eq(&active_catalog, catalog) {
1309                    return Err(RegistryCoordinationError::CatalogIdentityMismatch);
1310                }
1311                catalog.open();
1312                Ok(())
1313            }
1314            _ => Err(RegistryCoordinationError::OwnerMismatch),
1315        }
1316    }
1317
1318    /// 业务作用:按 owner 封口并撤销当前 managed catalog,阻止旧 Application 清理新实例。
1319    ///
1320    /// 参数说明:
1321    /// - `owner`:是正在逆序停机的 Application owner。
1322    ///
1323    /// 返回:owner 命中时撤销;不命中时保持现有权威并返回错误。
1324    pub fn clear_managed(
1325        &mut self,
1326        owner: &ManagedRegistryOwner,
1327    ) -> Result<(), RegistryCoordinationError> {
1328        match &self.state.mode {
1329            RegistryMode::Managed {
1330                owner: active,
1331                catalog,
1332            } => {
1333                let Some(active_owner) = active.upgrade() else {
1334                    return Err(RegistryCoordinationError::OwnerMismatch);
1335                };
1336                if !Arc::ptr_eq(&active_owner, &owner.0) {
1337                    return Err(RegistryCoordinationError::OwnerMismatch);
1338                }
1339                if let Some(catalog) = catalog.upgrade() {
1340                    catalog.stop_accepting();
1341                }
1342                self.state.mode = RegistryMode::Empty;
1343                Ok(())
1344            }
1345            _ => Err(RegistryCoordinationError::OwnerMismatch),
1346        }
1347    }
1348
1349    /// 业务作用:在 typed deferred pool 已被精确取走后清除 driver 记录。
1350    ///
1351    /// 参数说明:
1352    /// - `token`:当前 Application token。
1353    /// - `driver`:刚完成本地清理的 driver。
1354    ///
1355    /// 返回:owner 与 driver 匹配时清除记录;错配时保留模式。
1356    pub fn clear_deferred_driver(
1357        &mut self,
1358        token: &ManagedInstallationToken,
1359        driver: DatabaseDriver,
1360    ) -> Result<(), RegistryCoordinationError> {
1361        self.verify_bootstrap_owner(token)?;
1362        match &mut self.state.mode {
1363            RegistryMode::Bootstrapping {
1364                kind: BootstrapKind::DeferredDefault,
1365                deferred_driver: Some(active),
1366                ..
1367            } if *active == driver => {
1368                if let RegistryMode::Bootstrapping {
1369                    deferred_driver,
1370                    ..
1371                } = &mut self.state.mode
1372                {
1373                    *deferred_driver = None;
1374                }
1375                Ok(())
1376            }
1377            _ => Err(RegistryCoordinationError::DeferredDriverMissing),
1378        }
1379    }
1380
1381    /// 业务作用:在本轮 typed 资源全部清空后释放 Bootstrapping 占用。
1382    ///
1383    /// 参数说明:
1384    /// - `token`:是待撤销启动的 owner token。
1385    ///
1386    /// 返回:owner 匹配且没有 deferred 资源时回到 Empty;否则保留模式。
1387    pub fn abort_bootstrap(
1388        &mut self,
1389        token: &ManagedInstallationToken,
1390    ) -> Result<(), RegistryCoordinationError> {
1391        self.verify_bootstrap_owner(token)?;
1392        match &self.state.mode {
1393            RegistryMode::Bootstrapping {
1394                deferred_driver: Some(_),
1395                ..
1396            } => Err(RegistryCoordinationError::DeferredResourcesRemain),
1397            RegistryMode::Bootstrapping {
1398                ..
1399            } => {
1400                self.state.mode = RegistryMode::Empty;
1401                Ok(())
1402            }
1403            _ => Err(RegistryCoordinationError::OwnerMismatch),
1404        }
1405    }
1406
1407    /// 业务作用:返回协调锁保护下的低基数模式快照。
1408    ///
1409    /// 参数说明: 无。
1410    ///
1411    /// 返回:不暴露 owner、URL 或 datasource 名称的模式分类。
1412    pub fn snapshot(&self) -> RegistryModeSnapshot {
1413        match &self.state.mode {
1414            RegistryMode::Empty => RegistryModeSnapshot::Empty,
1415            RegistryMode::Standalone(driver) => RegistryModeSnapshot::Standalone(*driver),
1416            RegistryMode::Bootstrapping {
1417                owner,
1418                kind,
1419                deferred_driver,
1420            } => match (owner.upgrade(), deferred_driver) {
1421                (None, Some(driver)) => RegistryModeSnapshot::OrphanedDeferred(*driver),
1422                _ => RegistryModeSnapshot::Bootstrapping {
1423                    kind: *kind,
1424                    deferred_driver: *deferred_driver,
1425                },
1426            },
1427            RegistryMode::Managed {
1428                ..
1429            } => RegistryModeSnapshot::Managed,
1430        }
1431    }
1432
1433    /// 业务作用:复验 token 仍代表当前 Bootstrapping owner 与引导类型,阻止旧实例越权迁移状态。
1434    ///
1435    /// 参数说明:
1436    /// - `token`:是 typed driver 收到的安装凭据。
1437    ///
1438    /// 返回:owner Arc 身份与 kind 同时匹配时成功;其它状态返回 owner mismatch。
1439    fn verify_bootstrap_owner(
1440        &self,
1441        token: &ManagedInstallationToken,
1442    ) -> Result<(), RegistryCoordinationError> {
1443        match &self.state.mode {
1444            RegistryMode::Bootstrapping {
1445                owner,
1446                kind,
1447                ..
1448            } => {
1449                let Some(active) = owner.upgrade() else {
1450                    return Err(RegistryCoordinationError::OwnerMismatch);
1451                };
1452                if Arc::ptr_eq(&active, &token.owner.0) && *kind == token.kind {
1453                    Ok(())
1454                } else {
1455                    Err(RegistryCoordinationError::OwnerMismatch)
1456                }
1457            }
1458            _ => Err(RegistryCoordinationError::OwnerMismatch),
1459        }
1460    }
1461}
1462
1463/// 业务作用:读取当前进程 datasource 模式,供启动门禁和诊断复验。
1464///
1465/// 参数说明: 无。
1466///
1467/// 返回:已经执行弱 owner 自愈后的低基数模式快照。
1468pub fn registry_mode() -> RegistryModeSnapshot {
1469    coordinate(|coordinator| coordinator.snapshot())
1470}
1471
1472/// 业务作用:为 Application 领取唯一 owner 并进入配置建池或延后 default 的启动模式。
1473///
1474/// 参数说明:
1475/// - `kind`:指明 datasource 来自冻结配置还是 UserHook。
1476///
1477/// 返回:进程入口为空时返回 owner 与同身份 token;已有资源时不改变当前权威。
1478pub fn begin_managed_bootstrap(
1479    kind: BootstrapKind,
1480) -> Result<(ManagedRegistryOwner, ManagedInstallationToken), RegistryCoordinationError> {
1481    let owner = ManagedRegistryOwner::new();
1482    let token = coordinate(|coordinator| coordinator.begin_bootstrap(&owner, kind))?;
1483    Ok((owner, token))
1484}
1485
1486/// 业务作用:安装完整关闭态 catalog,形成尚不可读的 Managed 权威。
1487///
1488/// 参数说明:
1489/// - `token`:当前 Application 安装 token。
1490/// - `catalog`:已冻结且绑定同 owner 的 catalog。
1491///
1492/// 返回:owner 与模式匹配时完成安装;失败时 catalog 保持关闭。
1493pub fn install_managed_catalog(
1494    token: &ManagedInstallationToken,
1495    catalog: &Arc<DataSourceCatalog>,
1496) -> Result<(), RegistryCoordinationError> {
1497    coordinate(|coordinator| coordinator.install_catalog(token, catalog))
1498}
1499
1500/// 业务作用:在 typed registry 与资源容器全部提交后开放 managed catalog。
1501///
1502/// 参数说明:
1503/// - `token`:当前 Application 安装 token。
1504/// - `catalog`:必须是此前安装的同一 Arc。
1505///
1506/// 返回:身份复验通过时开放;失败时 getter 继续返回不可用。
1507pub fn open_managed_catalog(
1508    token: &ManagedInstallationToken,
1509    catalog: &Arc<DataSourceCatalog>,
1510) -> Result<(), RegistryCoordinationError> {
1511    coordinate(|coordinator| coordinator.open_catalog(token, catalog))
1512}
1513
1514/// 业务作用:在 driver 资源已封口后按 owner 撤销 managed catalog。
1515///
1516/// 参数说明:
1517/// - `owner`:是正在停机的 Application owner。
1518///
1519/// 返回:owner 命中时撤销;旧 owner 或非 Managed 模式返回错误且不影响新实例。
1520pub fn clear_managed_catalog(
1521    owner: &ManagedRegistryOwner,
1522) -> Result<(), RegistryCoordinationError> {
1523    coordinate(|coordinator| coordinator.clear_managed(owner))
1524}
1525
1526/// 业务作用:在 typed 资源尚未发布或已经清空时释放 Bootstrapping。
1527///
1528/// 参数说明:
1529/// - `token`:是待撤销启动的 owner token。
1530///
1531/// 返回:没有延后资源时回到 Empty;仍有资源时拒绝,要求先由对应 driver 精确清理。
1532pub fn abort_managed_bootstrap(
1533    token: &ManagedInstallationToken,
1534) -> Result<(), RegistryCoordinationError> {
1535    coordinate(|coordinator| coordinator.abort_bootstrap(token))
1536}
1537
1538/// 业务作用:解析全局 datasource 并复验 typed getter 的 driver 身份。
1539///
1540/// 参数说明:
1541/// - `datasource`:业务请求的 qualifier。
1542/// - `expected`:调用入口对应的 driver。
1543///
1544/// 返回:standalone、UserHook 延后引导期的同 driver `default`,或开放 managed catalog
1545/// 允许该 driver 时返回规范引用;其它模式返回结构化错误。
1546pub fn resolve_datasource(
1547    datasource: &str,
1548    expected: DatabaseDriver,
1549) -> Result<DatasourceRef, DataSourceLookupError> {
1550    coordinate(|coordinator| match &coordinator.state.mode {
1551        RegistryMode::Empty => {
1552            // 尚未安装任何 runtime 时只规范化名称,具体 typed registry 继续给出既有 NotFound 语义;
1553            // Bootstrapping 则必须保持不可读,不能把正在建立的权威误判成普通未初始化。
1554            DatasourceRef::new(datasource).map_err(|_| DataSourceLookupError::InvalidName)
1555        }
1556        RegistryMode::Bootstrapping {
1557            kind: BootstrapKind::DeferredDefault,
1558            deferred_driver: Some(actual),
1559            ..
1560        } if *actual == expected && datasource == DEFAULT_DATASOURCE => {
1561            // UserHook 只能在应用尚未 Ready 的窗口内使用刚注入的唯一 default;开放这条精确入口
1562            // 才能完成 schema 自举与运行时装配,命名库、另一 driver 和其它引导模式仍保持不可读。
1563            DatasourceRef::new(datasource).map_err(|_| DataSourceLookupError::InvalidName)
1564        }
1565        RegistryMode::Bootstrapping {
1566            ..
1567        } => Err(DataSourceLookupError::RegistryUnavailable),
1568        RegistryMode::Standalone(actual) if *actual == expected => {
1569            DatasourceRef::new(datasource).map_err(|_| DataSourceLookupError::InvalidName)
1570        }
1571        RegistryMode::Standalone(actual) => {
1572            let reference =
1573                DatasourceRef::new(datasource).map_err(|_| DataSourceLookupError::InvalidName)?;
1574            Err(DataSourceLookupError::DriverMismatch {
1575                datasource: reference,
1576                expected,
1577                actual: *actual,
1578            })
1579        }
1580        RegistryMode::Managed {
1581            catalog,
1582            ..
1583        } => catalog
1584            .upgrade()
1585            .ok_or(DataSourceLookupError::RegistryUnavailable)?
1586            .resolve(datasource, expected),
1587    })
1588}
1589
1590/// 业务作用:读取当前开放的 managed catalog,供 Application getter 与观测聚合使用。
1591///
1592/// 参数说明: 无。
1593///
1594/// 返回:Managed 且 catalog owner 仍存活时返回同一 Arc;其它模式返回不可用。
1595pub fn managed_catalog() -> Result<Arc<DataSourceCatalog>, DataSourceLookupError> {
1596    coordinate(|coordinator| match &coordinator.state.mode {
1597        RegistryMode::Managed {
1598            catalog,
1599            ..
1600        } => catalog
1601            .upgrade()
1602            .ok_or(DataSourceLookupError::RegistryUnavailable)
1603            .and_then(|catalog| match catalog.lifecycle.load(Ordering::Acquire) {
1604                CATALOG_OPEN => Ok(catalog),
1605                CATALOG_STOPPED => Err(DataSourceLookupError::Stopped),
1606                _ => Err(DataSourceLookupError::RegistryUnavailable),
1607            }),
1608        _ => Err(DataSourceLookupError::RegistryUnavailable),
1609    })
1610}