我正在使用 leveldb 板条箱,我正在尝试获取一个 Snapshot 结构并将其移动到我的结构中,但是我遇到了问题,因为我无法将引用的值移出函数。
这是来自 crate 的结构和特征的代码。我没有在这里包含它,但是 Database 类型实现了 Snapshots 特征以返回一个快照:
pub trait Snapshots<K: Key> {
fn snapshot<'a>(&'a self) -> Snapshot<'a, K>;
}
pub struct Snapshot<'a, K: Key + 'a> {
raw: RawSnapshot,
database: &'a Database<K>,
}
这是我的代码:
pub struct Cache {
ldb: RwLock<Database<i32>>
//other fields omitted
}
pub struct MySnapshot<'a> {
snapshot: Snapshot<'a, i32>
//other fields omitted
}
impl Cache {
pub fn snapshot<'a>(&'a self) -> MySnapshot<'a> {
let snapshot = self.ldb.read().unwrap().snapshot();
MySnapshot { snapshot }
}
}
我认为我不能这样做的原因(如果我错了,请纠正我)是使用 RwLock,当我获得对包装数据(在我的情况下为数据库)的引用时,该引用的生命周期不是 self 和所以当 RwLock 超出范围时它会被丢弃。我能想到的一种可能的解决方法是删除数据库上的 RwLock 并添加另一个字段:
pub struct Cache {
ldb: Database<i32>
//The wrapped type isn't important, just need this to make the function block
ldb_rwlock: RwLock<u8>
//other fields omitted
}
impl Cache {
pub fn snapshot<'a>(&'a self) -> MySnapshot<'a> {
self.ldb_rwlock.read();
let snapshot = self.ldb.snapshot();
MySnapshot { snapshot }
}
}
这将让我安全地获得快照,因为它会阻塞直到任何写锁被释放,并且最终用户除了通过我实现的 API 之外无法改变 ldb,只要我总是在尝试读/写之前使用 ldb_rwlock对 ldb 来说应该是安全的。但是,我觉得这会使 rust 打算使用 RwLock 的方式无效,并且感觉不是很惯用。有没有办法解决这个问题?
另外我不将 ldb 包装在 Arc 中的原因是因为 Cache 结构将被包装在 Arc 中并跨线程共享,我只想要锁定 ldb 字段,以便只有读/写数据库需要锁。不过,总的来说,我对生锈和并发性还是很陌生,所以我不确定我正在做的事情是否是解决这个问题的最佳方法。