Skip to main content

QotCache

Struct QotCache 

Source
pub struct QotCache {
    pub basic_qot: DashMap<SecurityKey, CachedBasicQot>,
    pub us_stock_overnight: DashMap<u64, bool>,
    pub klines: DashMap<String, Vec<CachedKLine>>,
    pub order_books: DashMap<SecurityKey, CachedOrderBook>,
    pub tickers: DashMap<SecurityKey, Vec<CachedTicker>>,
    pub rt_data: DashMap<String, Vec<CachedTimeShare>>,
    pub brokers: DashMap<SecurityKey, CachedBroker>,
    pub broker_dict: DashMap<i64, CachedBrokerInfo>,
    pub cold_cache_waiters: DashMap<String, Arc<Notify>>,
}
Expand description

行情缓存管理器

Fields§

§basic_qot: DashMap<SecurityKey, CachedBasicQot>

基本报价缓存

§us_stock_overnight: DashMap<u64, bool>

US stock overnight-enabled state, keyed by backend stock_id.

C++ stores this as stockID -> bool in INNData_Qot_USStockOvernight:

  • NNData_Qot_USStockOvernight.cpp:21-35 (missing key => false)
  • NNBiz_Qot_USStockState.cpp:180-190 writes overnight_type == 1
  • APIServer_Qot_MarketState.cpp:238-244 reads it for 11 -> 37 projection
§klines: DashMap<String, Vec<CachedKLine>>

K 线缓存: key = “market_code:kl_type”

§order_books: DashMap<SecurityKey, CachedOrderBook>

摆盘缓存

§tickers: DashMap<SecurityKey, Vec<CachedTicker>>

逐笔缓存: 保留最近 N 条

§rt_data: DashMap<String, Vec<CachedTimeShare>>

分时缓存 v1.4.106 codex 1140 F6 (P2 audit Finding 6): RT cache key 加 session 维度. 之前 DashMap<SecurityKey, ...> 把 RTH/ETH/PRE/AFTER 全部混到 同一桶, 客户端订阅 RTH 也能读到 PRE 数据. 现在 key 是 “sec_key:s{session}” (RequestSection 0=NORMAL/1=FULL/2=PREMARKET/ 3=AFTERHOURS), 隔离不同 session.

§brokers: DashMap<SecurityKey, CachedBroker>

经纪队列缓存

§broker_dict: DashMap<i64, CachedBrokerInfo>

v1.4.106 codex 1140 F7 (P2 audit Finding 7): 券商 ID → 信息映射. 由 CMD 18008 拉取后填充, 用于 push parser 从 broker_id 查真名 (替代 Broker#{bid} 占位符).

§cold_cache_waiters: DashMap<String, Arc<Notify>>

v1.4.110 codex Phase 3 Slice 6c: cold-cache wait waiters.

key = "<cache_key>:<wait_kind>" (e.g. "91_BTCUSDT@b1007:basic" / "1_00700:orderbook"). value = shared Arc<Notify> 让 handler 阻塞等 push parser 写 cache 后唤醒.

对齐 C++ APIServer_Qot_StockBasic.cpp:226-320 WaitForReady — 已订阅但 cache 未就绪时 handler 主动 Pull_SubData + 等 push 写 cache.

设计 trade-off:

  • DashMap<String, Arc<Notify>> 而非 RwLock<HashMap>: 高并发读 写不锁全表
  • key 编码 wait_kind 防 basic / orderbook 共用同一 Notify 互相错唤醒
  • update path 调 notify_waiters (broadcast 给所有 awaiter) 然后从 map 中 remove (Arc 被 awaiter 持有, 自然释放)

Implementations§

Source§

impl QotCache

Source

pub fn new() -> Self

Source

pub fn register_cold_cache_waiter(&self, wait_key: &str) -> Arc<Notify>

v1.4.110 codex Phase 3 Slice 6c: 注册 cold-cache wait waiter.

返已存在或新建的 Arc<Notify>. handler 调:

  1. register_cold_cache_waiter("91_BTCUSDT@b1007:basic") 获 Notify
  2. 主动发 Pull_SubData CMD6824
  3. tokio::time::timeout(Duration::from_secs(3), notify.notified())
  4. get_basic_qot_broker(&key) 读 cache (可能仍 None — 真 timeout)

wait_kind 推荐: "basic" / "orderbook". 不混 sub_type 数字防误唤.

Source

pub fn notify_cold_cache_waiters(&self, wait_key: &str)

v1.4.110 codex Phase 3 Slice 6c: 唤醒指定 cold-cache wait waiter.

push parser update path 调 (update_basic_qot / update_order_book / _broker 变种). 没 waiter → no-op. 有 waiter → notify_waiters() broadcast 给所有 awaiter, 然后 remove (Arc 仍被 awaiter 持有, 自然释放).

Source

pub fn cleanup_cold_cache_waiter_if_idle( &self, wait_key: &str, caller_notify: &Arc<Notify>, )

v1.4.110 codex audit Round3 #22: cold-cache wait timeout 后清 idle waiter.

wait_for_basic_cache / wait_for_order_book_cache 3s timeout 仍 cache miss 时调. 若 push 始终没来, notify_cold_cache_waiters 不会触发, entry 会一直留在 cold_cache_waiters map (虽 bounded by distinct wait_key 数, 仍是慢速 leak).

只删 caller 自己注册的那个 entry, 且无其他并发 awaiter 时才删: remove_if closure 在 entry lock 下原子检查两条:

  1. Arc::ptr_eq(stored, caller_notify) — stored 必须就是 caller 当初 register_cold_cache_waiter 拿到的同一 Arc. 防 race: caller timeout 后到本调用之间, 若 push 触发 notify_cold_cache_waiters 删了旧 entry, 另一个 wait_for_* 又 register 建了 entry (不同 Arc), ptr_eq false → 不误删别人的新 entry.
  2. Arc::strong_count(stored) <= 2 — DashMap stored Arc 1 + caller 持有的 caller_notify 1. > 2 表示有其他 wait_for_* 仍 await 同 entry → 保留让它们能被 notify 唤醒.

caller 约定: 必须把 register_cold_cache_waiter 返回的 Arc<Notify> 原样传进来 (caller 全程持有未 drop).

Source

pub fn set_us_stock_overnight_state(&self, stock_id: u64, is_overnight: bool)

Update C++-style US overnight stock state (stockID -> bool).

Ref: NNData_Qot_USStockOvernight.cpp:21-35 and NNBiz_Qot_USStockState.cpp:180-190.

Source

pub fn is_us_stock_overnight(&self, stock_id: u64) -> bool

Query whether a US stock is currently in overnight trading.

C++ cache miss returns false (NNData_Qot_USStockOvernight.cpp:29-34).

Source

pub fn get_broker_name(&self, broker_id: i64) -> Option<String>

v1.4.106 codex 1140 F7 (P2): 查 broker_id → broker name (中文简称). cache miss → None, 调用方决定 fallback 策略 (push parser 用 Broker#{id} 作 emergency fallback, 但同时 warn-log 提示 dict 未加载).

Source

pub fn install_broker_dict(&self, entries: Vec<(i64, CachedBrokerInfo)>)

v1.4.106 codex 1140 F7 (P2): 批量写入 broker dict (CMD 18008 解析后调).

Source

pub fn update_basic_qot(&self, key: &str, qot: CachedBasicQot)

更新基本报价

Source

pub fn get_basic_qot(&self, key: &str) -> Option<CachedBasicQot>

获取基本报价

Source

pub fn update_basic_qot_broker(&self, key: &QotSecurityKey, qot: CachedBasicQot)

v1.4.110 Phase 2 Slice 5: 更新基本报价 (broker-aware).

QotSecurityKey::cache_key() 派生 String key. broker_id=None → 与 update_basic_qot(public_sec_key, ...) 等价; broker_id=Some(N) → 写 独立 cache key "market_code@b{N}" (crypto multi-broker isolation).

Source

pub fn get_basic_qot_broker( &self, key: &QotSecurityKey, ) -> Option<CachedBasicQot>

v1.4.110 Phase 2 Slice 5: 获取基本报价 (broker-aware).

Source

pub fn make_rt_key(sec_key: &str, session: i32) -> String

构造 RT 分时 cache key (v1.4.106 codex 1140 F6).

之前 key 仅 sec_key, RTH/ETH/PRE/AFTER/OVERNIGHT 混桶. 现在 “sec_key:s{session}” 隔离. session 来自 push 解析的 TimeSharingPlans.section_type[0] (RequestSection enum): 0=NORMAL/1=FULL/2=PREMARKET/3=AFTERHOURS/5=OVERNIGHT. GetRT handler 对 C++ 的 Session_ETH/Session_ALL 读取语义做动态拼接, 不依赖额外 aggregate cache 桶。

Source

pub fn make_rt_key_broker(key: &QotSecurityKey, session: i32) -> String

v1.4.110 Phase 2 Slice 5: 构造 RT 分时 cache key (broker-aware).

QotSecurityKey::cache_key() 作 prefix. broker_id=None → 与 make_rt_key(public_sec_key, session) 等价; broker_id=Some(N) → 写 独立 cache key "market_code@b{N}:s{session}".

Source

pub fn update_rt_data_broker( &self, key: &QotSecurityKey, session: i32, rt_data: Vec<CachedTimeShare>, )

v1.4.110 Phase 2 Slice 5: 更新 RT 分时 (broker-aware).

Source

pub fn get_rt_data_broker( &self, key: &QotSecurityKey, session: i32, ) -> Option<Vec<CachedTimeShare>>

v1.4.110 Phase 2 Slice 5: 获取 RT 分时 (broker-aware).

Source

pub fn make_kline_key( sec_key: &str, rehab: i32, kl_type: i32, session: i32, ) -> String

构造 K 线 cache key (v1.4.106 codex 1140 F3 4-tuple).

之前 key 仅 (sec_key, kl_type) 2-tuple, 同股票同 KLType 但前复权 vs 后复权 / RTH vs ETH 数据互相覆盖. 对齐 C++ APIServer_Qot_KL.cpp: GetNewestKLByCount(stock_id, enRehabType, enKLType, num, session, ...) 用 4 维 key.

  • rehab: proto Qot_Common.RehabType (0=None, 1=Forward, 2=Backward), 对齐 backend FTCmdKline.ExrightType. 同一股票同一 kl_type 不同 rehab 走独立 cache, 不互相覆盖.
  • kl_type: proto Qot_Common.KLType (1=1Min, 2=Day, …, 11=Quarter).
  • session: proto FTCmdKline.RequestSection (0=NORMAL, 1=FULL, 2=PREMARKET, 3=AFTERHOURS). RTH/ETH 隔离, push 来自 backend 的 point.section_type[0] 决定写入桶, read 由 client subscription session 决定 (尚无, 默认 NORMAL).
Source

pub fn update_klines( &self, sec_key: &str, rehab: i32, kl_type: i32, session: i32, klines: Vec<CachedKLine>, )

更新 K 线 (v1.4.106 codex 1140 F3: 4-tuple key, rehab + session 隔离).

Source

pub fn get_klines( &self, sec_key: &str, rehab: i32, kl_type: i32, session: i32, ) -> Option<Vec<CachedKLine>>

获取 K 线 (v1.4.106 codex 1140 F3: 4-tuple key, rehab + session 隔离).

Source

pub fn update_klines_broker( &self, key: &QotSecurityKey, rehab: i32, kl_type: i32, session: i32, klines: Vec<CachedKLine>, )

v1.4.110 Phase 2 Slice 5: 更新 K 线 (broker-aware).

QotSecurityKey::cache_key() 作 prefix, broker_id=None 时退化到原行为. composite 维度仍是 4-tuple (rehab, kl_type, session), broker_id 是第 5 维通过 QotSecurityKey 注入到 prefix.

Source

pub fn get_klines_broker( &self, key: &QotSecurityKey, rehab: i32, kl_type: i32, session: i32, ) -> Option<Vec<CachedKLine>>

v1.4.110 Phase 2 Slice 5: 获取 K 线 (broker-aware).

Source

pub fn update_order_book(&self, key: &str, ob: CachedOrderBook)

更新摆盘

Source

pub fn update_order_book_broker( &self, key: &QotSecurityKey, ob: CachedOrderBook, )

v1.4.110 Phase 2 Slice 5: 更新摆盘 (broker-aware).

Source

pub fn get_order_book_broker( &self, key: &QotSecurityKey, ) -> Option<CachedOrderBook>

v1.4.110 Phase 2 Slice 5: 获取摆盘 (broker-aware).

Source

pub fn append_tickers(&self, key: &str, new_tickers: Vec<CachedTicker>)

追加逐笔(保留最近 1000 条)

Source

pub fn append_tickers_broker( &self, key: &QotSecurityKey, new_tickers: Vec<CachedTicker>, )

v1.4.110 Phase 2 Slice 5: 追加逐笔 (broker-aware).

Source

pub fn get_tickers_broker( &self, key: &QotSecurityKey, ) -> Option<Vec<CachedTicker>>

v1.4.110 Phase 2 Slice 5: 获取逐笔 (broker-aware).

Source

pub fn update_broker(&self, key: &str, broker: CachedBroker)

更新经纪队列

Source

pub fn get_broker(&self, key: &str) -> Option<CachedBroker>

获取经纪队列

Source

pub fn clear_security(&self, key: &str)

清除指定股票的所有缓存

Source

pub fn clear_security_broker(&self, key: &QotSecurityKey)

v1.4.110 Phase 2 Slice 5: 清除指定股票的所有缓存 (broker-aware).

QotSecurityKey::cache_key() 派生 cache key 字符串. broker_id=None → 与 clear_security(public_sec_key) 等价; broker_id=Some(N) → 只清 该 broker 下的 cache (其他 broker 下同 stock_id 的 cache 保留).

Trait Implementations§

Source§

impl Default for QotCache

Source§

fn default() -> Self

Returns the “default value” for a type. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

§

impl<T> Instrument for T

§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided [Span], returning an Instrumented wrapper. Read more
§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
§

impl<T> WithSubscriber for T

§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a [WithDispatch] wrapper. Read more
§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a [WithDispatch] wrapper. Read more