mirror of
https://github.com/pjh456/OxideJS.git
synced 2026-10-24 10:41:11 +08:00
feat: server forge 子命令,四张共享 forge 状态查询加三行动旗标
This commit is contained in:
@@ -0,0 +1,153 @@
|
||||
//! forge 状态查询:读四张共享 forge 的条目数与容量,执行三个行动旗标
|
||||
//! (gc / clear-cache / lookup)。
|
||||
//!
|
||||
//! `handle_forge_query` 是纯函数,参数全注入、无全局状态;worker 线程调用
|
||||
//! (gc 需触及本线程自有池),forge 状态读是跨线程安全的只读操作。
|
||||
|
||||
use std::sync::Arc;
|
||||
|
||||
use oxide_kernel::kernel::KernelCore;
|
||||
use oxide_vm::vm_pool::VmPool;
|
||||
|
||||
use super::protocol::{ForgeTarget, LookupResult, ServerResponse};
|
||||
|
||||
/// forge 查询处理:读目标 forge 状态,按旗标执行 gc / clear-cache / lookup,
|
||||
/// 组装 ForgeStatus 响应帧。
|
||||
///
|
||||
/// # 步骤
|
||||
/// 1. 读目标 forge 条目数与容量(code 目标容量取 max_cached_modules,其余 0)。
|
||||
/// 2. --gc 时对池内全体空闲 VM 执行完整 session GC,记收集数。
|
||||
/// 3. --clear-cache 时清空字节码 LRU 缓存。
|
||||
/// 4. --lookup 时在字符串 intern 表纯查询键的 id(不插入)。
|
||||
/// 5. 组装 ForgeStatus 响应帧返回。
|
||||
///
|
||||
/// # 边界与前提
|
||||
/// - 在 worker 线程调用(gc 需触及本线程自有池);forge 状态读是跨线程安全
|
||||
/// 的只读操作。
|
||||
/// - gc 只触及空闲队列,在借 VM(在途 eval)不受影响;clear-cache 清 LRU
|
||||
/// 不使在借模块失效(Arc 保活)。
|
||||
///
|
||||
/// # 副作用
|
||||
/// - --gc 重置各空闲 VM 的 session_bytes_allocated 为清扫后存活字节。
|
||||
/// - --clear-cache 清空字节码缓存(后续 eval 重编译)。
|
||||
pub fn handle_forge_query(
|
||||
target: ForgeTarget,
|
||||
gc: bool,
|
||||
clear_cache: bool,
|
||||
lookup: Option<String>,
|
||||
kernel: &Arc<KernelCore>,
|
||||
pool: &Arc<VmPool>,
|
||||
) -> ServerResponse {
|
||||
// 读目标 forge 条目数与容量。
|
||||
let (entries, capacity) = match target {
|
||||
ForgeTarget::Code => (kernel.code_forge().len(), kernel.max_cached_modules()),
|
||||
ForgeTarget::Object => (kernel.shape_forge().len(), 0),
|
||||
ForgeTarget::String => (kernel.perm_interner().entry_count() as usize, 0),
|
||||
ForgeTarget::Property => (kernel.prop_forge().len(), 0),
|
||||
};
|
||||
|
||||
// --gc:全体空闲 VM 完整 session GC。
|
||||
let gc_collected = gc.then(|| pool.collect_idle_gc());
|
||||
|
||||
// --clear-cache:清空字节码 LRU。
|
||||
let cache_cleared = if clear_cache {
|
||||
kernel.code_forge().clear();
|
||||
true
|
||||
} else {
|
||||
false
|
||||
};
|
||||
|
||||
// --lookup:字符串 intern 表纯查询(不插入)。
|
||||
let lookup_result = lookup.map(|key| match kernel.perm_interner().lookup_id(&key) {
|
||||
Some(id) => LookupResult::Interned { id },
|
||||
None => LookupResult::Absent,
|
||||
});
|
||||
|
||||
ServerResponse::ForgeStatus {
|
||||
target,
|
||||
entries,
|
||||
capacity,
|
||||
gc_collected,
|
||||
cache_cleared,
|
||||
lookup: lookup_result,
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::server::eval;
|
||||
use oxide_kernel::kernel::KernelConfig;
|
||||
|
||||
/// 测试环境:minimal 内核加单 VM 池(与 eval 测试同口径)。
|
||||
fn test_env() -> (Arc<KernelCore>, Arc<VmPool>) {
|
||||
let kernel = KernelCore::new(KernelConfig::minimal());
|
||||
let pool = VmPool::new(Arc::clone(&kernel), 1, Some(2));
|
||||
(kernel, pool)
|
||||
}
|
||||
|
||||
/// code 目标:容量等于 max_cached_modules,条目数 0(新内核),无旗标无行动结果。
|
||||
#[test]
|
||||
fn forge_query_code_entries() {
|
||||
let (kernel, pool) = test_env();
|
||||
let response = handle_forge_query(ForgeTarget::Code, false, false, None, &kernel, &pool);
|
||||
match response {
|
||||
ServerResponse::ForgeStatus {
|
||||
target,
|
||||
entries,
|
||||
capacity,
|
||||
gc_collected,
|
||||
cache_cleared,
|
||||
lookup,
|
||||
} => {
|
||||
assert_eq!(target, ForgeTarget::Code, "目标应为 code");
|
||||
assert_eq!(entries, 0, "新内核的字节码缓存应为空");
|
||||
assert_eq!(capacity, kernel.max_cached_modules(), "容量应等于 max_cached_modules");
|
||||
assert!(gc_collected.is_none(), "未设 gc 旗标应无收集数");
|
||||
assert!(!cache_cleared, "未设 clear-cache 旗标不应清缓存");
|
||||
assert!(lookup.is_none(), "未设 lookup 旗标应无结果");
|
||||
}
|
||||
other => panic!("应得 ForgeStatus 帧,实得 {other:?}"),
|
||||
}
|
||||
}
|
||||
|
||||
/// gc 旗标:先 eval 制造 session 状态归还池,再 gc 得收集数 Some(1)。
|
||||
#[test]
|
||||
fn forge_query_gc_collects() {
|
||||
let (kernel, pool) = test_env();
|
||||
eval::handle_eval("1 + 1", None, &kernel, &pool);
|
||||
let response = handle_forge_query(ForgeTarget::Code, true, false, None, &kernel, &pool);
|
||||
match response {
|
||||
ServerResponse::ForgeStatus { gc_collected, .. } => {
|
||||
assert_eq!(gc_collected, Some(1), "单 VM 池应收集 1 个空闲 VM");
|
||||
}
|
||||
other => panic!("应得 ForgeStatus 帧,实得 {other:?}"),
|
||||
}
|
||||
}
|
||||
|
||||
/// lookup:已 intern 键得 Interned,未 intern 键得 Absent,且纯查询不插入。
|
||||
#[test]
|
||||
fn forge_query_lookup() {
|
||||
let (kernel, pool) = test_env();
|
||||
let (id, _) = kernel.perm_interner().intern("forge-key");
|
||||
let before = kernel.perm_interner().entry_count();
|
||||
|
||||
let response = handle_forge_query(ForgeTarget::String, false, false, Some("forge-key".into()), &kernel, &pool);
|
||||
match response {
|
||||
ServerResponse::ForgeStatus { lookup, .. } => {
|
||||
assert_eq!(lookup, Some(LookupResult::Interned { id }), "已 intern 键应得该 id");
|
||||
}
|
||||
other => panic!("应得 ForgeStatus 帧,实得 {other:?}"),
|
||||
}
|
||||
|
||||
let response = handle_forge_query(ForgeTarget::String, false, false, Some("not-interned".into()), &kernel, &pool);
|
||||
match response {
|
||||
ServerResponse::ForgeStatus { lookup, .. } => {
|
||||
assert_eq!(lookup, Some(LookupResult::Absent), "未 intern 键应得 Absent");
|
||||
}
|
||||
other => panic!("应得 ForgeStatus 帧,实得 {other:?}"),
|
||||
}
|
||||
|
||||
assert_eq!(kernel.perm_interner().entry_count(), before, "纯查询不应插入新条目");
|
||||
}
|
||||
}
|
||||
@@ -2,13 +2,14 @@
|
||||
//!
|
||||
//! 持久 server 是常驻进程,复用预热池、近零 spawn 成本;
|
||||
//! 通信走 Unix socket + NDJSON(换行分隔 JSON)。
|
||||
//! 模块分七层:协议数据面(帧格式与 serde 结构体)、身份注册(sidecar 文件
|
||||
//! 模块分八层:协议数据面(帧格式与 serde 结构体)、身份注册(sidecar 文件
|
||||
//! 与 liveness 检查原语)、控制客户端(读 sidecar、连接 server、发控制请求
|
||||
//! 帧、读回响应帧、三分支错误)、执行请求路径(parse → compile → spawn →
|
||||
//! run → format → drop 六段纯函数)、worker 池(固定 N 常驻 worker、各持
|
||||
//! 自有 VM 池、mpsc 轮询路由)、server 进程主体(accept 循环、控制请求直接
|
||||
//! 处理、执行请求路由、优雅退出)、日志读取(行级别解析、阈值加最后 N 行
|
||||
//! 过滤、阻塞式跟踪)。
|
||||
//! 过滤、阻塞式跟踪)、forge 状态查询(读四张共享 forge 条目数与容量、执行
|
||||
//! gc / clear-cache / lookup 三旗标)。
|
||||
|
||||
/// 人工兜底清理命令:扫 sidecar、探活、杀 PID、删孤儿文件。
|
||||
pub mod cleanup;
|
||||
@@ -16,6 +17,9 @@ pub mod cleanup;
|
||||
pub mod client;
|
||||
/// 执行请求路径:parse → compile → spawn → run → format → drop 六段纯函数。
|
||||
pub mod eval;
|
||||
/// forge 状态查询:读四张共享 forge 条目数与容量,执行 gc / clear-cache /
|
||||
/// lookup 三旗标。
|
||||
pub mod forge;
|
||||
/// 日志读取:行级别解析、阈值加最后 N 行过滤、整文件读取、阻塞式跟踪。
|
||||
pub mod log;
|
||||
/// 协议数据面:NDJSON 帧格式与 serde 结构体。
|
||||
|
||||
@@ -48,7 +48,46 @@ impl ProtocolError {
|
||||
}
|
||||
}
|
||||
|
||||
/// server 请求帧:eval 执行请求加六类控制请求。
|
||||
/// forge 查询目标:四张共享 forge 之一。
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum ForgeTarget {
|
||||
/// 代码对象(字节码 LRU 缓存)。
|
||||
Code,
|
||||
/// 对象表(隐藏类 shape 表,含根节点)。
|
||||
Object,
|
||||
/// 字符串驻留(intern 键表)。
|
||||
String,
|
||||
/// 属性表(属性模板缓存)。
|
||||
Property,
|
||||
}
|
||||
|
||||
impl ForgeTarget {
|
||||
/// 目标名(小写),供渲染与展示。
|
||||
pub fn as_str(self) -> &'static str {
|
||||
match self {
|
||||
ForgeTarget::Code => "code",
|
||||
ForgeTarget::Object => "object",
|
||||
ForgeTarget::String => "string",
|
||||
ForgeTarget::Property => "property",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// lookup 结果:已 intern(带稳定 id)或未 intern。
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
#[serde(tag = "status", rename_all = "snake_case")]
|
||||
pub enum LookupResult {
|
||||
/// 已 intern,附稳定 id。
|
||||
Interned {
|
||||
/// intern 键的稳定 id。
|
||||
id: u32,
|
||||
},
|
||||
/// 未 intern。
|
||||
Absent,
|
||||
}
|
||||
|
||||
/// server 请求帧:eval 执行请求、forge 状态查询加六类控制请求。
|
||||
///
|
||||
/// 序列化为 tagged 对象,`type` 字段区分类型(snake_case)。
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
@@ -61,6 +100,20 @@ pub enum ServerRequest {
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
max_steps: Option<u64>,
|
||||
},
|
||||
/// forge 状态查询:目标 forge 加三个行动旗标(gc / clear_cache / lookup)。
|
||||
ForgeQuery {
|
||||
/// 目标 forge:code / object / string / property。
|
||||
target: ForgeTarget,
|
||||
/// 触发垃圾回收(对池内全体空闲 VM 执行完整 session GC)。
|
||||
#[serde(default, skip_serializing_if = "std::ops::Not::not")]
|
||||
gc: bool,
|
||||
/// 清空字节码 LRU 缓存。
|
||||
#[serde(default, skip_serializing_if = "std::ops::Not::not")]
|
||||
clear_cache: bool,
|
||||
/// 在字符串 intern 表纯查询一个键的 id(不插入)。
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
lookup: Option<String>,
|
||||
},
|
||||
/// 查询 server 版本。
|
||||
Version,
|
||||
/// 查询 server 状态(池与运行时长)。
|
||||
@@ -90,6 +143,24 @@ pub enum ServerResponse {
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
error: Option<String>,
|
||||
},
|
||||
/// forge 状态响应:目标 forge 条目数与容量,加三个行动结果。
|
||||
ForgeStatus {
|
||||
/// 目标 forge:code / object / string / property。
|
||||
target: ForgeTarget,
|
||||
/// 目标 forge 的条目数(object 目标含根节点)。
|
||||
entries: usize,
|
||||
/// 容量上限(code 目标为 LRU 上限,其余为 0 表示无界)。
|
||||
capacity: usize,
|
||||
/// --gc 收集的空闲 VM 数;未设旗标为 None。
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
gc_collected: Option<usize>,
|
||||
/// --clear-cache 已执行时为真。
|
||||
#[serde(default, skip_serializing_if = "std::ops::Not::not")]
|
||||
cache_cleared: bool,
|
||||
/// --lookup 结果;未设旗标为 None。
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
lookup: Option<LookupResult>,
|
||||
},
|
||||
/// 版本响应。
|
||||
Version { version: String },
|
||||
/// 状态响应:池可用/总数、峰值借出数与运行时长。
|
||||
@@ -130,10 +201,12 @@ impl ServerResponse {
|
||||
}
|
||||
|
||||
/// 请求帧可取的 `type` 值(须与 `ServerRequest` 变体保持同步)。
|
||||
const REQUEST_TAGS: &[&str] = &["eval", "version", "status", "health", "info", "shutdown", "yield"];
|
||||
const REQUEST_TAGS: &[&str] =
|
||||
&["eval", "forge_query", "version", "status", "health", "info", "shutdown", "yield"];
|
||||
|
||||
/// 响应帧可取的 `type` 值(须与 `ServerResponse` 变体保持同步)。
|
||||
const RESPONSE_TAGS: &[&str] = &["eval_result", "version", "status", "health", "info", "shutdown", "yield", "error"];
|
||||
const RESPONSE_TAGS: &[&str] =
|
||||
&["eval_result", "forge_status", "version", "status", "health", "info", "shutdown", "yield", "error"];
|
||||
|
||||
/// 序列化请求为帧字符串(含结尾换行)。
|
||||
///
|
||||
@@ -357,6 +430,83 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
/// forge 查询请求 round-trip:四目标各一轮,带与不带三旗标两形态。
|
||||
#[test]
|
||||
fn forge_query_roundtrip() {
|
||||
for target in [ForgeTarget::Code, ForgeTarget::Object, ForgeTarget::String, ForgeTarget::Property] {
|
||||
roundtrip_request(&ServerRequest::ForgeQuery {
|
||||
target,
|
||||
gc: false,
|
||||
clear_cache: false,
|
||||
lookup: None,
|
||||
});
|
||||
roundtrip_request(&ServerRequest::ForgeQuery {
|
||||
target,
|
||||
gc: true,
|
||||
clear_cache: true,
|
||||
lookup: Some("key".into()),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/// forge 状态响应 round-trip:含 gc_collected 与 lookup 两 Some 形态与全省略形态。
|
||||
#[test]
|
||||
fn forge_status_roundtrip() {
|
||||
for resp in [
|
||||
ServerResponse::ForgeStatus {
|
||||
target: ForgeTarget::Code,
|
||||
entries: 0,
|
||||
capacity: 512,
|
||||
gc_collected: None,
|
||||
cache_cleared: false,
|
||||
lookup: None,
|
||||
},
|
||||
ServerResponse::ForgeStatus {
|
||||
target: ForgeTarget::String,
|
||||
entries: 42,
|
||||
capacity: 0,
|
||||
gc_collected: Some(3),
|
||||
cache_cleared: true,
|
||||
lookup: Some(LookupResult::Interned { id: 7 }),
|
||||
},
|
||||
ServerResponse::ForgeStatus {
|
||||
target: ForgeTarget::Object,
|
||||
entries: 1,
|
||||
capacity: 0,
|
||||
gc_collected: None,
|
||||
cache_cleared: false,
|
||||
lookup: Some(LookupResult::Absent),
|
||||
},
|
||||
] {
|
||||
roundtrip_response(&resp);
|
||||
}
|
||||
}
|
||||
|
||||
/// 序列化形态:forge_query 省略空旗标,lookup 省略 None。
|
||||
#[test]
|
||||
fn forge_query_serialization_shape() {
|
||||
assert_eq!(
|
||||
serde_json::to_string(&ServerRequest::ForgeQuery {
|
||||
target: ForgeTarget::Code,
|
||||
gc: false,
|
||||
clear_cache: false,
|
||||
lookup: None,
|
||||
})
|
||||
.unwrap(),
|
||||
r#"{"type":"forge_query","target":"code"}"#
|
||||
);
|
||||
assert_eq!(
|
||||
serde_json::to_string(&ServerRequest::ForgeQuery {
|
||||
target: ForgeTarget::String,
|
||||
gc: true,
|
||||
clear_cache: false,
|
||||
lookup: Some("k".into()),
|
||||
})
|
||||
.unwrap(),
|
||||
r#"{"type":"forge_query","target":"string","gc":true,"lookup":"k"}"#
|
||||
);
|
||||
}
|
||||
|
||||
/// 序列化形态:eval 请求省略空 max_steps,控制请求无载荷字段。
|
||||
#[test]
|
||||
fn request_serialization_shape() {
|
||||
|
||||
@@ -10,8 +10,9 @@
|
||||
//! - accept 循环为非阻塞 accept 加 10 毫秒轮询加原子关闭标志:唤醒路径
|
||||
//! 确定、无锁、无唤醒丢失。
|
||||
//! - 并发模型:主线程只跑 accept 循环;每连接一个标准库线程只做 I/O
|
||||
//! (帧读写);六类控制请求由连接线程直接应答、不占 worker;执行请求
|
||||
//! 经 mpsc 路由到固定 N 个常驻 worker 执行(各持自己线程上的 VM 池)。
|
||||
//! (帧读写);六类控制请求由连接线程直接应答、不占 worker;执行请求与
|
||||
//! forge 查询经 mpsc 路由到固定 N 个常驻 worker 执行(各持自己线程上的
|
||||
//! VM 池)。
|
||||
//! - 优雅退出顺序:关闭请求、SIGINT/SIGTERM 信号或 yield 请求置位关闭标志
|
||||
//! → 在途归零 → 清空发送端 → join worker → drop 内核 → 先删 socket 文件
|
||||
//! 后删 sidecar(新 server 以 sidecar 消失为接管信号)。
|
||||
@@ -32,7 +33,7 @@ use oxide_kernel::kernel::{KernelConfig, KernelCore};
|
||||
use oxide_log::{Level, LogConfig, Output, SUBSYSTEM_COUNT};
|
||||
use oxide_vm::vm_pool::PoolCounters;
|
||||
|
||||
use super::protocol::{self, FrameReader, ProtocolError, ServerRequest, ServerResponse};
|
||||
use super::protocol::{self, ForgeTarget, FrameReader, ProtocolError, ServerRequest, ServerResponse};
|
||||
use super::sidecar::{self, ClaimResult};
|
||||
use super::workers::{self, WorkerRouter};
|
||||
|
||||
@@ -617,8 +618,8 @@ fn accept_loop(
|
||||
/// # 步骤
|
||||
/// 1. 克隆写端,原流交给帧读取器,设读超时(`read_timeout` 参数)。
|
||||
/// 2. 循环读帧:EOF、读超时、非法 UTF-8 退出;帧长超限按协议约定关连接。
|
||||
/// 3. 畸形帧以 `Error` 帧答复后继续;执行请求路由到 worker 并阻塞等回复;
|
||||
/// 控制请求直接应答并写回。
|
||||
/// 3. 畸形帧以 `Error` 帧答复后继续;执行请求与 forge 查询经 worker 路由
|
||||
/// 并阻塞等回复;控制请求直接应答并写回。
|
||||
/// 4. 关闭或 yield 确认帧写回即退出循环。
|
||||
///
|
||||
/// # 边界与前提
|
||||
@@ -645,6 +646,12 @@ fn handle_connection(stream: UnixStream, ctx: &ServerContext, router: &WorkerRou
|
||||
// 执行请求走 worker 路由,控制请求直接应答。
|
||||
let response = match protocol::parse_request(&frame) {
|
||||
Ok(ServerRequest::Eval { code, max_steps }) => dispatch_eval(&code, max_steps, router),
|
||||
Ok(ServerRequest::ForgeQuery {
|
||||
target,
|
||||
gc,
|
||||
clear_cache,
|
||||
lookup,
|
||||
}) => dispatch_forge(target, gc, clear_cache, lookup, router),
|
||||
Ok(request) => dispatch_control(&request, ctx),
|
||||
Err(ProtocolError::FrameTooLarge) => break,
|
||||
Err(error) => error.to_error_frame(),
|
||||
@@ -684,6 +691,32 @@ fn dispatch_eval(code: &str, max_steps: Option<u64>, router: &WorkerRouter) -> S
|
||||
}
|
||||
}
|
||||
|
||||
/// forge 查询分派:路由到 worker 执行(读 forge 状态加可选 gc / clear-cache /
|
||||
/// lookup),阻塞在一次性回复通道上取回响应帧。
|
||||
///
|
||||
/// # 步骤
|
||||
/// 1. 建一次性回复通道,发送端随任务进 worker。
|
||||
/// 2. 轮询投递到 worker;发送端已清空(关闭序列进行中)时立即以错误帧答复。
|
||||
/// 3. 阻塞 recv 至回复;worker 已退出(通道断开)时以错误帧答复,不挂起。
|
||||
fn dispatch_forge(
|
||||
target: ForgeTarget, gc: bool, clear_cache: bool, lookup: Option<String>, router: &WorkerRouter,
|
||||
) -> ServerResponse {
|
||||
let (reply_tx, reply_rx) = std::sync::mpsc::channel();
|
||||
let task = workers::WorkerTask::ForgeQuery {
|
||||
target,
|
||||
gc,
|
||||
clear_cache,
|
||||
lookup,
|
||||
reply: reply_tx,
|
||||
};
|
||||
match router.route(task) {
|
||||
Ok(()) => reply_rx
|
||||
.recv()
|
||||
.unwrap_or_else(|_| ServerResponse::eval_err("worker 已退出,forge 查询未处理")),
|
||||
Err(_) => ServerResponse::eval_err("server 正在关闭,forge 查询未受理"),
|
||||
}
|
||||
}
|
||||
|
||||
/// 控制请求分派:六类控制请求直接应答,不占 worker。
|
||||
///
|
||||
/// Status 响应读全体 worker 池的共享聚合计数器。
|
||||
@@ -714,9 +747,10 @@ fn dispatch_control(request: &ServerRequest, ctx: &ServerContext) -> ServerRespo
|
||||
ctx.shutdown.store(true, Ordering::SeqCst);
|
||||
ServerResponse::Yield
|
||||
}
|
||||
// 防御性兜底:正常路径 eval 在调用本函数前已被拦截走 worker 路由;
|
||||
// 若到达此臂说明上游分流缺失,以错误帧答复而非静默执行。
|
||||
// 防御性兜底:正常路径 eval 与 forge 查询在调用本函数前已被拦截走
|
||||
// worker 路由;若到达此臂说明上游分流缺失,以错误帧答复而非静默执行。
|
||||
ServerRequest::Eval { .. } => ServerResponse::eval_err("执行请求应经 worker 路由,不应到达控制分派"),
|
||||
ServerRequest::ForgeQuery { .. } => ServerResponse::eval_err("forge 查询应经 worker 路由,不应到达控制分派"),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -17,7 +17,8 @@ use oxide_kernel::kernel::KernelCore;
|
||||
use oxide_vm::vm_pool::{PoolCounters, VmPool};
|
||||
|
||||
use super::eval;
|
||||
use super::protocol::ServerResponse;
|
||||
use super::forge;
|
||||
use super::protocol::{ForgeTarget, ServerResponse};
|
||||
|
||||
/// worker 任务:执行请求加一次性回复通道。
|
||||
#[derive(Debug)]
|
||||
@@ -28,6 +29,14 @@ pub enum WorkerTask {
|
||||
max_steps: Option<u64>,
|
||||
reply: mpsc::Sender<ServerResponse>,
|
||||
},
|
||||
/// forge 查询:目标 forge 加三个行动旗标,一次性回复通道。
|
||||
ForgeQuery {
|
||||
target: ForgeTarget,
|
||||
gc: bool,
|
||||
clear_cache: bool,
|
||||
lookup: Option<String>,
|
||||
reply: mpsc::Sender<ServerResponse>,
|
||||
},
|
||||
}
|
||||
|
||||
/// worker 路由器:N 条独立任务通道的发送端加轮询计数。
|
||||
@@ -125,6 +134,16 @@ fn worker_loop(receiver: mpsc::Receiver<WorkerTask>, kernel: Arc<KernelCore>, po
|
||||
let response = eval::handle_eval(&code, max_steps, &kernel, &pool);
|
||||
let _ = reply.send(response);
|
||||
}
|
||||
WorkerTask::ForgeQuery {
|
||||
target,
|
||||
gc,
|
||||
clear_cache,
|
||||
lookup,
|
||||
reply,
|
||||
} => {
|
||||
let response = forge::handle_forge_query(target, gc, clear_cache, lookup, &kernel, &pool);
|
||||
let _ = reply.send(response);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user