Rust分布式数据库插件holochain_sqlite的使用:支持SQLite存储的Holochain数据持久化与高效查询
Rust分布式数据库插件holochain_sqlite的使用:支持SQLite存储的Holochain数据持久化与高效查询
holochain_sqlite是一个用于Holochain持久化状态的构建模块,当前版本为0.0.1。
历史背景
最初这个crate是为LMDB设计的,在稳定后我们完全重构了它,改用SQLite作为键值存储。这是为将来更智能和全面地使用SQLite做准备,通过精心选择的索引和查询来优化性能。但目前,这个crate的结构只能在这个重大重构的背景下理解。
后端:SQLite
持久化实现专门针对SQLite后端。未来如果需要更换后端或支持IndexedDb等,我们将适当泛化接口以兼顾两者。
缓冲存储(Buffered Stores)
持久化Holochain状态的基本单元是BufferedStore。这个接口将三部分组合在一起:
- SQLite数据库引用
- 只读事务引用(与其他存储共享)
- “暂存空间” - 用于暂存写操作的HashMap(缓冲区)
暂存空间的目的是避免需要打开读写事务(同一时间只能有一个)。通过暂存空间缓冲区,存储引用可以存在更长时间,累积更改,然后在短暂的读写事务中一次性刷新缓冲区。
BufferedStore包含对只读事务的引用,这意味着存储作为构造时持久数据的快照。底层持久化的更改不会反映在这个BufferedStore中。
强类型
所有BufferedStore都是强类型的。所有键和值必须可序列化/反序列化,因此在将项目放入存储时自动进行序列化/反序列化。因此,源链CAS被分成两个独立的数据库:一个用于Entries,另一个用于Actions。
工作区(Workspaces)
Holochain代码不直接处理单个数据存储。BufferedStores总是分组到Workspace中,Workspace是为特定目的组合的存储集合。工作区可以选择提供对底层存储的开放访问,或者将它们保护在专门构建的接口后面。
Workspace中的存储都提供共同的只读事务,因此它们的快照在工作区构建时彼此一致。工作区提供自己的接口与存储交互。一旦更改累积在BufferedStores中,工作区本身可以被提交,这使用新的读写事务从每个存储刷新更改并提交到磁盘。提交会消耗工作区。
构建模块
holochain_sqlite crate提供三种缓冲KV存储抽象以及一个简单的CAS抽象:
- KvBuf:普通KV存储
- KvIntBuf:键必须为整数的KV存储(使用LMDB时有意义,但现在不重要)
- KvvBuf:每个键有多个值的KV存储,支持按键迭代
- CasBuf:强制键必须是值"地址"(内容)的KvBuf
holochain crate将这些构建模块组合在一起构建更特定目的的BufferedStore实现。
示例代码
use holochain_sqlite::prelude::*;
use rusqlite::Connection;
// 创建SQLite连接
let conn = Connection::open_in_memory().unwrap();
// 创建缓冲KV存储
let mut kv_store = KvBuf::new(&conn);
// 插入数据
kv_store.put("key1".to_string(), "value1".to_string()).unwrap();
kv_store.put("key2".to_string(), "value2".to_string()).unwrap();
// 获取数据
let value = kv_store.get(&"key1".to_string()).unwrap();
assert_eq(value, Some("value1".to_string()));
// 创建整数键KV存储
let mut int_store = KvIntBuf::new(&conn);
int_store.put(1, "int_value1".to_string()).unwrap();
int_store.put(2, "int_value2".to_string()).unwrap();
// 创建CAS存储
let mut cas_store = CasBuf::new(&conn);
cas_store.put("address1", "content1".to_string()).unwrap();
完整示例
use holochain_sqlite::{kv::KvBuf, sqlite::rusqlite::Connection};
use serde::{Serialize, Deserialize};
#[derive(Debug, Clone, Serialize, Deserialize)]
struct Person {
name: String,
age: u32,
}
fn main() -> anyhow::Result<()> {
// 创建内存数据库
let conn = Connection::open_in_memory()?;
// 初始化KV存储
let mut kv_store = KvBuf::new(&conn);
// 存储自定义结构
let person = Person {
name: "Alice".to_string(),
age: 30,
};
kv_store.put("person1".to_string(), person.clone())?;
// 获取数据
let retrieved: Option<Person> = kv_store.get(&"person1".to_string())?;
println!("Retrieved person: {:?}", retrieved);
// 创建事务并提交
let tx = conn.transaction()?;
kv_store.flush(&tx)?;
tx.commit()?;
Ok(())
}
贡献
Holochain是一个开源项目。我们欢迎各种形式的参与,并积极扩大接受参与的范围。
许可证
CAL-1.0许可证
版权所有©2019-2024,Holochain基金会
本程序是自由软件:您可以根据许可证条款重新分发和修改它。
Rust分布式数据库插件holochain_sqlite使用指南
概述
holochain_sqlite是一个为Holochain应用提供SQLite存储支持的Rust插件,它实现了高效的数据持久化和查询功能,特别适合需要本地数据库支持的分布式应用开发。
主要特性
- 为Holochain提供SQLite后端存储
- 支持高效的数据持久化
- 提供灵活的查询能力
- 与Holochain DNA无缝集成
- 轻量级且高性能
安装方法
在Cargo.toml中添加依赖:
[dependencies]
holochain_sqlite = "0.1.0"
完整示例代码
use holochain_sqlite::prelude::*;
use holochain_types::prelude::*;
#[tokio::main]
async fn main() -> SqliteDbResult<()> {
// 1. 初始化SQLite存储
let db_path = "holochain_data.db";
let sqlite = SqliteStorage::new(db_path).await?;
sqlite.initialize().await?;
// 2. 存储示例数据
let entry = Entry::try_from(SerializedBytes::try_from(
r#"{"name":"test","value":42}"#,
)?)?;
let header_hash = HeaderHash::from_raw_32(vec![0; 32]);
let entry_hash = EntryHash::from_raw_32(vec![1; 32]);
sqlite.store_entry(&header_hash, &entry_hash, &entry).await?;
// 3. 查询数据
let retrieved_entry = sqlite.get_entry(&entry_hash).await?;
println!("Retrieved entry: {:?}", retrieved_entry);
// 4. 高级查询
let high_value_entries = advanced_query(&sqlite).await?;
println!("Entries with value > 40: {}", high_value_entries.len());
// 5. 性能优化
optimize_database(&sqlite).await?;
Ok(())
}
async fn advanced_query(sqlite: &SqliteStorage) -> SqliteDbResult<Vec<Entry>> {
use rusqlite::params;
let mut conn = sqlite.connection().await?;
let mut stmt = conn.prepare(
"SELECT entry_blob FROM entries WHERE json_extract(entry_blob, '$.value') > ?"
)?;
let entries = stmt
.query_map(params![40], |row| {
let blob: Vec<u8> = row.get(0)?;
Entry::try_from(SerializedBytes::from_unchecked(blob.into()))
})?
.collect::<Result<Vec<_>, _>>()?;
Ok(entries)
}
async fn optimize_database(sqlite: &SqliteStorage) -> SqliteDbResult<()> {
// 创建索引
sqlite.execute(
"CREATE INDEX IF NOT EXISTS idx_entry_value ON entries(json_extract(entry_blob, '$.value'))"
).await?;
// 设置PRAGMA优化参数
sqlite.execute("PRAGMA journal_mode = WAL").await?;
sqlite.execute("PRAGMA synchronous = NORMAL").await?;
sqlite.execute("PRAGMA cache_size = -10000").await?;
Ok(())
}
集成到Holochain DNA
在DNA配置文件中添加SQLite存储配置:
---
manifest_version: "1"
name: my_dna
integrity:
network_seed: "my_network_seed"
properties: ~
origin_time: "2023-01-01T00:00:00.000000Z"
zomes:
- name: my_zome
bundled: target/wasm32-unknown-unknown/release/my_zome.wasm
dependencies: ~
coordinator:
zomes: ~
storage:
type: sqlite
path: "./dna_data.db"
注意事项
- 在多线程环境中使用时,确保正确处理连接池
- SQLite文件路径需要有写入权限
- 大型数据集应考虑分片策略
- 定期备份重要数据