zenoh 存储插件的处理简单说明
zenoh 的存储插件实际上内部也是调用的,zenoh 暴露的session 操作的,对于数据的写入式基于了subscriber,对于数据的查询是基于了zenoh 的queryable,以下是一个简单说明完整的可以参考实际源码
内部处理
上边简单说明了下,内部实际上就是zenoh 的session 处理包含了订阅以及可查询定义,插件是在zenoh 服务启动的时候加载的(存储插件管理服务)
- 存储插件接口定义 如下图可以看到包含了,get,put,delete,以及status等接口
#[async_trait]
pub trait Storage: Send + Sync {
/// Returns the status that will be sent as a reply to a query
/// on the administration space for this storage.
fn get_admin_status(&self) -> serde_json::Value;
/// Function called for each incoming data ([`Sample`](zenoh::sample::Sample)) to be stored in this storage.
/// A key can be `None` if it matches the `strip_prefix` exactly.
/// In order to avoid data loss, the storage must store the `value` and `timestamp` associated with the `None` key
/// in a manner suitable for the given backend technology
async fn put(
&mut self,
key: Option<OwnedKeyExpr>,
value: Value,
timestamp: Timestamp,
) -> ZResult<StorageInsertionResult>;
/// Function called for each incoming delete request to this storage.
/// A key can be `None` if it matches the `strip_prefix` exactly.
/// In order to avoid data loss, the storage must delete the entry corresponding to the `None` key
/// in a manner suitable for the given backend technology
async fn delete(
&mut self,
key: Option<OwnedKeyExpr>,
timestamp: Timestamp,
) -> ZResult<StorageInsertionResult>;
/// Function to retrieve the sample associated with a single key.
/// A key can be `None` if it matches the `strip_prefix` exactly.
/// In order to avoid data loss, the storage must retrieve the `value` and `timestamp` associated with the `None` key
/// in a manner suitable for the given backend technology
async fn get(
&mut self,
key: Option<OwnedKeyExpr>,
parameters: &str,
) -> ZResult<Vec<StoredData>>;
/// Function called to get the list of all storage content (key, timestamp)
/// The latest Timestamp corresponding to each key is either the timestamp of the delete or put whichever is the latest.
/// Remember to fetch the entry corresponding to the `None` key
async fn get_all_entries(&self) -> ZResult<Vec<(Option<OwnedKeyExpr>, Timestamp)>>;
}
- 服务处理
storage service 中定义的
pub(crate) async fn start_storage_queryable_subscriber(
self: Arc<Self>,
mut rx: Receiver<StorageMessage>,
) {
// start periodic GC event
let t = Timer::default();
let gc_config = self.configuration.garbage_collection_config.clone();
let latest_updates = if self.cache_latest.replication_log.is_none() {
Some(self.cache_latest.latest_updates.clone())
} else {
None
};
let gc = TimedEvent::periodic(
gc_config.period,
GarbageCollectionEvent {
config: gc_config,
wildcard_deletes: self.wildcard_deletes.clone(),
wildcard_puts: self.wildcard_puts.clone(),
latest_updates,
},
);
t.add_async(gc).await;
let storage_key_expr = &self.configuration.key_expr;
// subscribe on key_expr 特定key expression 订阅
let storage_sub = match self.session.declare_subscriber(storage_key_expr).await {
Ok(storage_sub) => storage_sub,
Err(e) => {
tracing::error!("Error starting storage '{}': {}", self.name, e);
return;
}
};
// answer to queries on key_expr queryable 定义
let storage_queryable = match self
.session
.declare_queryable(storage_key_expr)
.complete(self.configuration.complete)
.await
{
Ok(storage_queryable) => storage_queryable,
Err(e) => {
tracing::error!("Error starting storage '{}': {}", self.name, e);
return;
}
};
内部处理(对于数据进行查询以及存储处理)
tokio::task::spawn(async move {
loop {
tokio::select!(
// on sample for key_expr
sample = storage_sub.recv_async() => {
let sample = match sample {
Ok(sample) => sample,
Err(e) => {
tracing::error!("Error in sample: {}", e);
continue;
}
};
let timestamp = sample.timestamp().cloned().unwrap_or(self.session.new_timestamp());
let sample = SampleBuilder::from(sample).timestamp(timestamp).into();
// process_sample 会进行一些处理,然后调用上边存储插件定义的put方法
if let Err(e) = self.process_sample(sample).await {
tracing::error!("{e:?}");
}
},
// on query on key_expr
query = storage_queryable.recv_async() => {
// 会调用存储的get方法对于通过get 获取数据的处理
self.reply_query(query).await;
},
// on storage handle drop
Ok(message) = rx.recv() => {
match message {
StorageMessage::Stop => {
tracing::trace!("Dropping storage '{}'", self.name);
return
},
StorageMessage::GetStatus(tx) => {
let storage = self.storage.lock().await;
std::mem::drop(tx.send(storage.get_admin_status()).await);
drop(storage);
}
};
},
);
}
});
说明
以上是一个简单说明,可以看到zenoh 存储插件内部并没有比较特殊的地方,还是使用了zenoh session 的能力(具体处理都在内部),实际上zenoh 通过存储插件管理服务进行存储插件的统一管理,实际上存储插件管理还有对于数据复制的处理(数据一致性处理),后边介绍
参考资料
plugins/zenoh-plugin-storage-manager/src/storages_mgt/service.rs
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)
2023-12-28 mrml 使用中的一些问题
2023-12-28 elixir mjml_nif 试用
2023-12-28 mrml python 以及webassembly 实现简单说明
2023-12-28 mrml mjml 的rust 实现
2022-12-28 gitlab 集成的一些SAST安全扫描工具
2022-12-28 dremio ClassCompilerSelector 简单说明
2022-12-28 dremio SabotContext 简单说明