包装的LMDB游标迭代器的惯用创建

时间:2019-04-25 17:08:10

标签: rust lifetime ownership lmdb

我在创建一个迭代器来封装LMDB迭代器和rust事务时遇到了麻烦。

我使用的是lmdb crate,它包装了C LMDB绑定,似乎无法找到使事务保持活动状态和游标/迭代器的方法。删除事务后,游标/它不再有效,并且我得到了错误事务mdb_cursor_get returned an unexpected error: -30782

的LMDB错误代码

为解决此问题,我尝试将Transaction包装到其自己的结构中。包装迭代器的创建时,将Transaction结构作为arg传递,以尝试使Transaction保持活动状态,但是由于某些冲突的生命周期问题,看来不起作用。

pub struct Accessor {
    db_env: Environment,
    db: Database,
}

pub struct Accessor {
    pub fn contents(
        &self,
    ) -> Result<impl Iterator<Item=(EntryKey, EntryValue)> + '_>
    {
        let mut iter_factory = IterFactory::new(&self.db_env, &self.db);
        let it = iter_factory.iter_start();
        Ok(it)
    }
}
#[derive(Debug)]
pub struct IterFactory<'a> {
    txn: Box<RoTransaction<'a>>,
    db: &'a Database,
}

impl <'a> IterFactory<'a> {
    pub fn new(db_env: &'a Environment, db: &'a Database) -> IterFactory<'a> {
        let txn = db_env.begin_ro_txn().expect("Error opening up ROTransaction on LMDB!");
        IterFactory{txn: Box::new(txn), db: db, iter: None}
    }

    pub fn iter_start(&mut self) -> EntryIterator<'a> {
        let mut cursor = self.txn.open_ro_cursor(*self.db).expect("Error opening up ROCursor on LMDB!");
        let iter = cursor.iter_start();
        EntryIterator::new(self, iter)
    }
}

#[derive(Debug)]
pub struct EntryIterator<'a> {
    iter_factory: &'a mut IterFactory<'a>,
    inner_iter: Iter<'a>,
    max_key: EntryKey,
}

impl<'a> EntryIterator<'a> {
    fn new(iter_factory: &'a mut IterFactory<'a>, iter: Iter<'a>) -> EntryIterator<'a> {
        EntryIterator {iter_factory: iter_factory, inner_iter: iter, max_key: SEG_KEY_MAX }
    }

    pub fn up_to(mut self, max_key: EntryKey) -> EntryIterator<'a> {
        self.max_key = max_key;
        self
    }
}

impl<'a> Iterator for EntryIterator<'a> {
    type Item = (EntryKey, EntryValue);

    fn next(&mut self) -> Option<Self::Item> {
        let res = self.inner_iter.next();

        if res == None {
            return None;
        }

        let (key, val) = res.unwrap();
        let key_val: EntryKey = EntryKey::from_bytes(key);
        if key_val > self.max_key {
            None
        } else {
            let entry_val: EntryValue = EntryValue::from_bytes(val);
            Some((key_val, entry_val))
        }
    }
}

这种尝试会产生一些我不太熟悉的奇怪的终身问题。

error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements
    |
401 |         EntryIterator::new(self, iter)
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^
    |
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the method body at 398:5...
    |
398 | /     pub fn iter_start(&mut self) -> EntryIterator<'a> {
399 | |         let mut cursor = self.txn.open_ro_cursor(*self.db).expect("Error opening up ROCursor on LMDB!");
400 | |         let iter = cursor.iter_start();
401 | |         EntryIterator::new(self, iter)
402 | |     }
    | |_____^
note: ...so that reference does not outlive borrowed content
    |
401 |         EntryIterator::new(self, iter)
    |                                   ^^^^
note: but, the lifetime must be valid for the lifetime 'a as defined on the impl at 392:7...
    |
392 | impl <'a> IterFactory<'a> {
    |       ^^
    = note: ...so that the expression is assignable:
            expected &mut log::index::IterFactory<'_>
               found &mut log::index::IterFactory<'a>

0 个答案:

没有答案