pub struct StaticDataCache {
pub securities: DashMap<String, CachedSecurityInfo>,
pub id_to_key: DashMap<u64, String>,
pub trade_dates: DashMap<String, Vec<CachedTradeDate>>,
pub plates: DashMap<String, Vec<CachedPlateInfo>>,
pub owner_to_warrants: RwLock<HashMap<u64, HashSet<u64>>>,
pub stale_mkt_ids: DashMap<String, ()>,
pub mkt_id_refresh_marked_total: AtomicU64,
pub mkt_id_refresh_done_total: AtomicU64,
pub mkt_id_refresh_failed_total: AtomicU64,
/* private fields */
}Expand description
静态数据缓存
Fields§
§securities: DashMap<String, CachedSecurityInfo>股票静态信息: “market_code” → info
v1.4.106 codex 1148 F9: 对外 read-only。生产代码不应直接 .insert()
这个 DashMap (会导致 id_to_key / owner_to_warrants 三索引不一致),
必须走 upsert_full_security_info / upsert_basic_security_info /
delete_security_info 统一写入口。pub 仅为 backwards-compat:
既有迭代 caller (snapshot.rs for-iter .iter()) 仍能 read-only 遍历。
id_to_key: DashMap<u64, String>stock_id → “market_code” key (反向映射,用于推送时查找)
v1.4.106 codex 1148 F9: 对外 read-only (同 securities)。
trade_dates: DashMap<String, Vec<CachedTradeDate>>交易日: “market:year-month” → Vec
plates: DashMap<String, Vec<CachedPlateInfo>>板块: “market:plate_type” → Vec
owner_to_warrants: RwLock<HashMap<u64, HashSet<u64>>>窝轮正股 owner_id → 该正股对应的所有窝轮 stock_id 集合
v1.4.106 codex 1148 F6: value 从 Vec<u64> 改为 HashSet<u64> 防
重复 (SQLite reload + stock-list re-sync 同 warrant 多次 push 不会再重复).
stock-list delete_flag 时反向索引清理: 旧 owner 下移除旧 warrant
(delete_security_info 内部维护), update 时也维护。
stale_mkt_ids: DashMap<String, ()>v1.4.89 P2-A: 需要 mkt_id refresh 的 cache key 集合.
Callers get_security_info_trigger_refresh 在返 info 前检查
info.needs_mkt_id_refresh(), 是则 mark key 到这里. 背景 worker
(gateway bridge) 定期 drain_stale_mkt_ids() 批量 CMD 20106 refresh.
用 DashMap<String, ()> 替代 HashSet
mkt_id_refresh_marked_total: AtomicU64v1.4.89 P2-A: mkt_id refresh 统计计数, 用于 metrics 观察.
mkt_id_refresh_marked_total: 累积 mark stale 次数mkt_id_refresh_done_total: 累积 backend CMD 20106 成功 refresh 次数mkt_id_refresh_failed_total: 累积 refresh failure 次数
mkt_id_refresh_done_total: AtomicU64§mkt_id_refresh_failed_total: AtomicU64Implementations§
Source§impl StaticDataCache
impl StaticDataCache
pub fn new() -> Self
Sourcepub fn get_security_info_trigger_refresh(
&self,
key: &str,
) -> Option<CachedSecurityInfo>
pub fn get_security_info_trigger_refresh( &self, key: &str, ) -> Option<CachedSecurityInfo>
v1.4.89 P2-A: 取 cache info 同时机会性 mark stale (若 mkt_id=0).
返 Some(info) 如果 cache hit (无论是否 stale). 返 None 如果 miss.
调 info.needs_mkt_id_refresh() 判 stale → mark stale_mkt_ids,
bump mkt_id_refresh_marked_total counter. 用 DashMap::insert 幂等
(同 key 重入不 double mark 但会 bump counter — 可接受).
替代 get_security_info 的推荐路径; 老 method 保留作 lookup-only 接口.
Sourcepub fn mark_stale_mkt_id(&self, key: &str)
pub fn mark_stale_mkt_id(&self, key: &str)
v1.4.89 P2-A: 显式 mark key 需要 mkt_id refresh.
幂等: 同 key 可重入. Counter mkt_id_refresh_marked_total 每次都 bump
(用作 metrics 观察 heuristic fallback 触发频率).
Sourcepub fn drain_stale_mkt_ids(&self) -> Vec<String>
pub fn drain_stale_mkt_ids(&self) -> Vec<String>
v1.4.89 P2-A: drain 所有 stale keys, 清空集合, 返 Vec (给 backend worker 批量 CMD 20106 refresh).
背景 worker 用法 (伪码):
loop {
sleep(Duration::from_secs(60)).await;
let stale = cache.drain_stale_mkt_ids();
if stale.is_empty() { continue; }
for chunk in stale.chunks(50) {
// CMD 20106 SecuritiesReq for chunk
// on success: cache.update_mkt_id(key, new_mkt_id)
// + cache.record_mkt_id_refresh_done()
// on failure: cache.record_mkt_id_refresh_failed()
}
}Sourcepub fn update_mkt_id(&self, key: &str, new_mkt_id: u32) -> bool
pub fn update_mkt_id(&self, key: &str, new_mkt_id: u32) -> bool
v1.4.89 P2-A: 更新已 cache row 的 mkt_id (refresh success 时调).
只改 mkt_id 字段, 其他字段保留 (info 可能有 SQLite 里更精准的 lot_size / list_time 等). 若 key 不在 cache (已被 evict), no-op.
Sourcepub fn record_mkt_id_refresh_failed(&self)
pub fn record_mkt_id_refresh_failed(&self)
v1.4.89 P2-A: 记录 refresh failure (不改 cache row, 让下次 drain 重试).
Sourcepub fn stale_mkt_ids_count(&self) -> usize
pub fn stale_mkt_ids_count(&self) -> usize
v1.4.89 P2-A: 当前 stale keys 数 (给 observability / debug).
Sourcepub fn upsert_full_security_info(&self, key: &str, info: CachedSecurityInfo)
pub fn upsert_full_security_info(&self, key: &str, info: CachedSecurityInfo)
v1.4.106 codex 1148 F9 (P3): 统一写入口 — 完整静态行 (StockListFull /
Bootstrap source)。同步维护 securities + id_to_key + 若有 owner
还更新 owner_to_warrants。自动 dedup: 已有同 key 但 warrnt_stock_owner
变化时, 旧 owner 下移除该 warrant id, 新 owner 下添加。
替代生产代码里手动调 securities.insert() + id_to_key.insert() +
add_warrant_owner() 三步骤的 pattern。
不允许 caller 把不完整的 source 标 StockListFull(若 info.source == OnDemandBasic, 用 upsert_basic_security_info 而非本 fn)。
Sourcepub fn upsert_crypto_pair_info(&self, key: &str, pair: CryptoPairInfo)
pub fn upsert_crypto_pair_info(&self, key: &str, pair: CryptoPairInfo)
写入 stock-list 下发的 crypto 货币对元数据。
Sourcepub fn get_crypto_pair_info(&self, key: &str) -> Option<CryptoPairInfo>
pub fn get_crypto_pair_info(&self, key: &str) -> Option<CryptoPairInfo>
读取 crypto 货币对元数据。
Sourcepub fn set_crypto_trade_configs_for_broker(
&self,
broker_id: u32,
configs: Vec<CryptoTradeConfig>,
)
pub fn set_crypto_trade_configs_for_broker( &self, broker_id: u32, configs: Vec<CryptoTradeConfig>, )
用 backend CMD20102 拉回的配置替换某个 broker 的 crypto trade config。
Sourcepub fn get_crypto_trade_config(
&self,
broker_id: u32,
symbol: &str,
exchange: &str,
) -> Option<CryptoTradeConfig>
pub fn get_crypto_trade_config( &self, broker_id: u32, symbol: &str, exchange: &str, ) -> Option<CryptoTradeConfig>
查询某个 crypto symbol 的交易配置。
Sourcepub fn upsert_basic_security_info(&self, key: &str, info: CachedSecurityInfo)
pub fn upsert_basic_security_info(&self, key: &str, info: CachedSecurityInfo)
v1.4.106 codex 1148 F9 (P3): 统一写入口 — 部分静态行 (OnDemandBasic
source)。同步维护 securities + id_to_key, 不动 owner_to_warrants
(因为 OnDemandBasic 不含 warrnt_stock_owner 字段, value 必为 0)。
info.source 必须是 OnDemandBasic (debug_assert)。
Sourcepub fn delete_security_info(&self, stock_id: u64) -> bool
pub fn delete_security_info(&self, stock_id: u64) -> bool
v1.4.106 codex 1148 F9 (P3): 删除 cache row + 同步清三个索引
(securities, id_to_key, owner_to_warrants)。
用于 stock-list delete_flag = true 场景。
返 true 如果 row 存在并被删除, false 如果 stock_id 不在 id_to_key。
Sourcepub fn get_future_main_link_alias_keys(&self, stock_id: u64) -> Vec<String>
pub fn get_future_main_link_alias_keys(&self, stock_id: u64) -> Vec<String>
查询某个 backend push stock_id 对应的主连/连续合约 sec_key 别名。
只返回 stock-list 明确下发 origin_id / zhuli_id 关系的 key;不做
HSImain 等字符串启发式。调用方通常先按 id_to_key 处理真实合约,
再把这里返回的 main-link key 一并投递。
Sourcepub fn quote_push_targets_for_stock_id(
&self,
stock_id: u64,
) -> Vec<(String, CachedSecurityInfo)>
pub fn quote_push_targets_for_stock_id( &self, stock_id: u64, ) -> Vec<(String, CachedSecurityInfo)>
查询 backend push stock_id 的所有 quote 投递目标。
顺序保持为:真实 stock_id 对应 key(如有)优先,然后是 stock-list
origin_id / zhuli_id 下发的主连/连续合约别名 key。调用方不再直接
读取 id_to_key 和 future_main_link_aliases 两个索引,避免 alias 逻辑
分散在 push parser 里。
Sourcepub fn quote_push_targets_for_stock_key(
&self,
stock_id: u64,
broker_id: Option<NonZeroU32>,
) -> Vec<(QotSecurityKey, CachedSecurityInfo)>
pub fn quote_push_targets_for_stock_key( &self, stock_id: u64, broker_id: Option<NonZeroU32>, ) -> Vec<(QotSecurityKey, CachedSecurityInfo)>
v1.4.110 Phase 2 Slice 5: broker-aware 推送投递目标查询.
对应 push parser 从 SecurityQuote.broker_id 重建 broker-aware
QotStockKey 的路径 (对齐 C++ NNBiz_Qot_PushQot.cpp:220-269).
语义:
broker_id = None(C++m_hasBroker=false): 只查 no-broker key, 返QotSecurityKey::no_broker(public_sec_key, stock_id)与quote_push_targets_for_stock_id等价broker_id = Some(N)(C++m_hasBroker=true): 沿 stock_id 反向 找到 public_sec_key, 再用QotSecurityKey::from_broker_id(...)构造 broker-aware key. 该 broker 下 cache 写入独立桶"market_code@b{N}", 不污染同 stock_id 其他 broker 的 cache.
Phase 2 默认: backend 当前对普通股 push 仍不下发 broker_id (=None),
与升级前行为完全等价. crypto multi-broker push 会带 broker_id,
Phase 3 reader caller (handler GetBasicQot 等) 替换走 _broker
版本后, broker-aware cache 才被消费.
Sourcepub fn set_security_info(&self, key: &str, info: CachedSecurityInfo)
👎Deprecated since 1.4.106: use upsert_full_security_info / upsert_basic_security_info / delete_security_info
pub fn set_security_info(&self, key: &str, info: CachedSecurityInfo)
deprecated: 改用 upsert_full_security_info /
upsert_basic_security_info 维护三索引一致性。本 method 仅写
securities, 不更新 id_to_key / owner_to_warrants — 直接调
会产生半索引行 (按 code 查得到, 按 stock_id 反向查不到)。
v1.4.106 codex 1148 F9 起仅保留作 unit test / bench 兼容。生产代码
禁用 (review-time grep set_security_info 须 0 命中 in crates/futu-*/src/)。
pub fn get_security_info(&self, key: &str) -> Option<CachedSecurityInfo>
Sourcepub fn get_security_info_by_stock_id(
&self,
stock_id: u64,
) -> Option<CachedSecurityInfo>
pub fn get_security_info_by_stock_id( &self, stock_id: u64, ) -> Option<CachedSecurityInfo>
通过 stock_id 查找股票信息 (使用 id_to_key 反向映射)
Sourcepub fn add_warrant_owner(&self, warrant_stock_id: u64, owner_stock_id: u64)
pub fn add_warrant_owner(&self, warrant_stock_id: u64, owner_stock_id: u64)
添加窝轮→正股的映射关系
v1.4.106 codex 1148 F6: HashSet 自动去重, 重复 add 同 (warrant, owner) 是 idempotent — SQLite reload + stock-list sync 不会重复入。
Sourcepub fn search_warrants_by_owner(&self, owner_stock_id: u64) -> Vec<u64>
pub fn search_warrants_by_owner(&self, owner_stock_id: u64) -> Vec<u64>
通过正股 ID 搜索该正股的所有窝轮
v1.4.106 codex 1148 F6: 内部 HashSet, 返 Vec (call site backward compatible)。返序非确定 (HashSet 不保留 insertion order); call site 若 需要稳定序应自己 sort。